This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

SeaMeet API Documentation

Overview

SeaMeet API provides powerful tools for managing meetings, processing audio recordings, and generating intelligent meeting insights. This API enables developers to integrate advanced meeting management features including real-time transcription, speaker diarization, and automated meeting summarization.

Key Features

Meeting Management

  • Create and manage meetings from audio recordings
  • Support for Google Meet integration and uploaded audio files
  • Automatic detection of meeting participants and speakers

Audio Processing

  • High-accuracy speech-to-text transcription
  • Multi-language support with dialect recognition
  • Speaker separation and identification (diarization)

Intelligent Insights

  • Automated meeting summaries with action items
  • Conversation analytics and participation metrics
  • Customizable summary templates

Integration Support

  • Webhook notifications for meeting status updates
  • Real-time transcription streaming
  • Export capabilities for transcripts and summaries

Getting Started

Prerequisites

  1. Create a SeaMeet workspace through the SeaMeet Dashboard. If you don’t have an account yet, sign up here
  2. Obtain API key.
  3. Install required client libraries or use REST API directly

Authentication

All interactions with the SeaMeet API require proper authentication using Bearer token authentication. This security mechanism ensures that only authorized applications and users can access your workspace and agent data.

Bearer Token Authentication

Every API request must include an Authorization header with your API key formatted as a Bearer token. The header format is:

Authorization: Bearer [your-access-token]

Replace [your-access-token] with your actual API key. This token provides full access to your workspace, so it should be treated as a sensitive credential.

1 - Audio Upload

API endpoint for creating meetings from audio recordings

Overview

Create a new meeting by analyzing audio recordings. The analyze_audio endpoint handles audio uploads, initiates processing, and returns a job ID for tracking analysis progress.

Quick Start

Step 0: Authentication and Set up

  1. Make sure you have completed prerequisites here
  2. If you would like to receive results via callback, you need to follow steps here

Step 1: Prepare Audio File

Prepare the audio to be uploaded. Not the following limitations:

Supported Languages

Language CodeLanguage
da-DKDanish (Denmark)
de-DEGerman (Germany)
en-GBEnglish (United Kingdom)
en-INEnglish (India)
en-USEnglish (United States)
es-ESSpanish (Spain)
es-MXSpanish (Mexico)
fi-FIFinnish (Finland)
fr-FRFrench (France)
he-ILHebrew (Israel)
hi-INHindi (India)
id-IDIndonesian (Indonesia)
it-ITItalian (Italy)
ja-JPJapanese (Japan)
ko-KRKorean (South Korea)
pl-PLPolish (Poland)
pt-BRPortuguese (Brazil)
pt-PTPortuguese (Portugal)
sv-SESwedish (Sweden)
zh-CNMandarin (China)
zh-TWMandarin (Taiwan)

Supported formats

wav/pcm, wav/alaw, wav/mulaw, mp3, mp4, ogg/opus, flac, wma, aac, amr, webm, speex.

Audio duration

Maximum of 2 hours.

File size

Maximum of 300MB

Step 2: Create Meeting

Create SeaMeet meeting instance. See API

Step 3: Upload Audio

First obtain a presigned s3 url and then upload audio to the provided url. See API

Step 4: Run Analysis

  1. Start the transcription and analysis job. See API
  2. Check analysis job status using the job ID See API

Step 5: Get Results

There are two ways to check the results:

  • Receive results via callback, make sure you have followed steps here before submitting the analysis job.
  • Check results on SeaMeet

Create Meeting

API

POST https://meet.seasalt.ai/seameet-api/api/v1/workspaces/{workspace_id}/meetings

NameValueDescription
acceptapplication/json
AuthorizationBearer {access_token}Bearer token

Request Body

NameTypeDescriptionExampleRequired
meeting_namestringName of the meeting“call_1”
channel_typestringType of the meeting, must be the same as workspace type for now“PHONE”
languagestringLanguage of the meeting, should be in [“en-US”, “zh-TW”]“zh-TW”
start_timestringUTC Datetime of when the audio began following the ISO 8601 standard. Make sure this matches the timezone setting in the workspace.“2024-05-30T21:53:34”
resource_metadataobjectOptional. Custom data column. Normally, it would fill customer local call id for data consistency.{"call_id": "123"}✖️

Response Status 200

Normal response with the created workspace info.

Status code: 200
Example of the response body
{
  id: "seax_139953cfd9e612d6c7827ccebdd7c50c",
  owner_id: "useraccount",
  name: "Meeting Name",
  participants_number: 0,
  status: "INITIAL",
  start_time: "2022-12-07T10:11:42.520327",
  language: "en-US",
  duration: 0,
  flag: "WAITING",
  channel_type: "PHONE",
}

Delete Meeting

API

DELETE https://meet.seasalt.ai/seameet-api/api/v1/workspaces/{workspace_id}/meetings/{meeting_id}

Header

NameValueDescription
acceptapplication/json
AuthorizationBearer {access_token}Bearer token

Response Status 204

No payload return

Generate Audio Upload URL

API

POST https://meet.seasalt.ai/seameet-api/api/v1/workspaces/{workspace_id}/meetings/{meeting_id}/upload_audio_url

Header

NameValueDescription
acceptapplication/json
AuthorizationBearer {access_token}Bearer token

Request Body

NameTypeDescriptionExampleRequired
namestringFile name, if raise error if conflicts"file_name.wav"

Response Status 200

Normal response with the created workspace info.

Status code: 200
Example of the response body
{
  upload_audio_url: "https://xxxxx",
  expired_time: "2024-05-30T21:53:34" // utc
}
and then upload file to upload_audio_urlwith curl command
curl -X PUT -T "/path/to/file" "https://xxxxx"

or use the python script below.

import requests

url = 'https://xxxxx'
file_path = '/path/to/file'

with open(file_path, 'rb') as f:
    response = requests.put(url, data=f)

print(response.status_code)  # 200

Response Status 400

MeetingNotFoundError

Status code: 400

Run Analysis

Upload an audio file to create a SeaMeet meeting and run analysis on transcriptions.

API

POST https://meet.seasalt.ai/seameet-api/api/v1/workspaces/{workspace_id}/meetings/{meeting_id}/analyze_audio

Header

NameValueDescription
acceptapplication/json
AuthorizationBearer {access_token}Bearer token

Request Body

NameTypeDescriptionExampleRequired
channelsnumberNumber of channels for the audio, needs to be 1 or 21
file_namestringfile_name of the uploaded audiofile_name.wav✖️
audio_start_offsetnumberAudio start offset from the start of the meeting.10.5✖️
audio_formatstringAudio file format, inferred from path extension if not provided.wav✖️
audio_sample_ratenumberAudio file sample rate, inferred from file header if not provided.8000✖️
audio_encodingstringAudio file encoding, inferred from file header if not provided.pcm_s16le✖️
scenariostringScenario of this audio, e.g. customer_service_callcustomer_service_call✖️
scenario_parametersobjectDictionary containing fields specific to the scenario, see scenario_parameters for customer_service_call{"went_to_voicemail": false, "spoke_to_agent": true}✖️
speaker_accountsstringOptional. The speaker accounts.["kontak_customer_181"]✖️
diarization_optionsstringeither by_server or disabled, meaning enable and disable diarization respectively.by_server✖️

scenario_parameters for customer_service_call

NameTypeDescriptionExampleRequired
customer_numberstringCustomer call number.0933123456
went_to_voicemailboolWhether the call went straight to voicemail without being picked up.false✖️
contains_recordingsboolWhether recordings like voicemail or automated voice messages are present in the audio.false✖️
spoke_to_agentboolWhether the customer spoke to a live agent. Only applicable for inbound calls. If true for inbound calls, went_to_voicemail is ignored.true✖️
customer_namestringCustomer name.John Doe✖️
agent_namestringAgent name.Jane Doe✖️

Response Status 202

The file was successfully uploaded and the data import process started.

Status code: 202
Response body
NameTypeDescriptionExample
idstringJob ID for the current job. It can be used to query the execution result or compare it with the data obtained from the callback.55c09c56-9f99-4da2-bba4-da4722759e02
typestringJob type for the current job. It would always be MEETING_ANALYSIS for this endpoint.MEETING_ANALYSIS
statusstringIndicates the status of the job QUEUED, FINISHED, FAILED, or STARTED. The analysis will be sent to callback_url after the status changes to FINISHED for a period of time.QUEUED
resultnullStay null value through all status.null
error_messagestringnullWhen an error occurs, it returns error information; otherwise, it is null if no errors occur
relationsobjectIt would contain two keys: “workspace_id”, “meeting_id”. All of the keys have their id.{"meeting_id": "55c09c56-9f99-4da2-bba4-da4722759e01", "workspace_id": "55c09c56-9f99-4da2-bba4-da4722759e02" }
parametersobjectIt would contain the whole input payload.See example below
Example of the response body
{
  "job":{
    "id": "55c09c56-9f99-4da2-bba4-da4722759e08",
    "type": "MEETING_ANALYSIS",
    "relations": {
       "meeting_id": "55c09c56-9f99-4da2-bba4-da4722759e01",
       "workspace_id": "55c09c56-9f99-4da2-bba4-da4722759e02"
    },
    "parameters": {
      "channels": 1,
      "audio_start_offset": 10.5,
      "audio_format": "wav",
      "audio_sample_rate": 8000,
      "audio_encoding": "pcm_s16le",
     "diarization_options": "by_server",
     "num_speakers": 2,
     "enable_itn": true,
     "enable_punctuation": true,
      "scenario": "customer_service_call",
      "scenario_parameters": {
        "went_to_voicemail": false,
        "contains_recordings": false,
        "spoke_to_agent": true,
        "customer_number": "0933123456",
        "customer_name": "John Doe",
        "agent_name": "Jane Doe",
        "num_speakers": 2
      },
    },
    "status": "QUEUED",
    "error_message": null,
    "result": null
  }
}

Response Status 400

AudioNotFoundError

Status code: 400

Get Job by ID

Query job information

API

GET https://meet.seasalt.ai/seameet-api/api/v1/workspaces/{workspace_id}/jobs/{job_id}

Header

NameValueDescription
acceptapplication/json
AuthorizationBearer {access_token}Bearer token

Response Status 200

Normal response with the requested job data

Status code: 200
Response body
NameTypeDescriptionExample
idstringThe job id.55c09c56-9f99-4da2-bba4-da4722759e08
typestringThe type of job.MEETING_ANALYSIS
statusstringIndicates the status of the job QUEUED, FINISHED, FAILED, or STARTED. The analysis will be sent to callback_url after the status changes to FINISHED for a period of time.QUEUED
resultnullStay null value through all statusSee example below
error_messagestringnullWhen an error occurs, it returns error information; otherwise, it is null if no errors occur
relationsobjectIt would contain two keys: “workspace_id”, “meeting_id”. All of the keys have their id.{"meeting_id": "55c09c56-9f99-4da2-bba4-da4722759e01", "workspace_id": "55c09c56-9f99-4da2-bba4-da4722759e02" }
parametersobjectIt would contain the whole input payload.See example below
Example of the response body
{
  "id": "55c09c56-9f99-4da2-bba4-da4722759e08",
  "type": "MEETING_ANALYSIS",
  "status": "FINISHED",
  "result": null,
  "relations": {
     "meeting_id": "55c09c56-9f99-4da2-bba4-da4722759e01",
     "workspace_id": "55c09c56-9f99-4da2-bba4-da4722759e02"
  },
  "parameters": {
    "channels": 1,
    "audio_start_offset": 10.5,
    "audio_format": "wav",
    "audio_sample_rate": 8000,
    "audio_encoding": "pcm_s16le",
    "scenario": "customer_service_call",
    "scenario_parameters": {
      "went_to_voicemail": false,
      "contains_recordings": false,
      "spoke_to_agent": true,
      "customer_number": "0933123456",
      "customer_name": "John Doe",
      "agent_name": "Jane Doe",
      "num_speakers": 2
    }
  },
  "status": "QUEUED",
  "error_message": null,
  "result": null
}

Response Status 404

The requested data does not exist.

Status code: 404

Callback API

Callback for Call Analysis

The callback API specifications for call analysis. IMPORTANT

  • Each workspace has its dedicated callback url and callback metadata (optional). Please contact info@seasalt.ai.
  • Developers should implement their callback APIs according to the following schema to successfully accept SeaMeet analysis callbacks.
  • The key of X-Seasalt-Server-Signature would be provided to you we’ve set up your workspace with the provided callback settings.

Header

namevalueDescription
acceptapplication/json
X-Seasalt-Server-SignatureHMAC(k, m, h) m: json body in utf-8. k: each workspace having random ASCII letters (both uppercase and lowercase) and digits in total length 32. h: sha256 The result will be presented as hexadecimal digits.For security issue

Method: POST

Request Body

nametypeDescriptionexample
payloadPayload objectAnalysis results formatted in json string.See example below
event_namestrShould be dashboard_analysis_finished"dashboard_analysis_finished"
meeting_idstringThe meeting id of analyzed meeting"seax_bd4aeffdf09520dd077c7e541b9ae577"
workspace_idstringThe workspace id of the meeting"xxx"

Payload

This is an example payload with some sample analysis items like customer_satisfaction

nametypeDescriptionexample
meeting_idstringThe meeting id of analyzed meeting"seax_bd4aeffdf09520dd077c7e541b9ae577"
customer_satisfaction_ratingstringThe customer satisfaction rating during the meeting. The score ranges from A to E, with A representing the best and E the worst. If the value is null, it means there is insufficient information to make a judgment.A
agent_performance_ratingstringThe agent performance rating during the meeting. The score ranges from A to E, with A representing the best and E the worst. If the value is null, it means there is insufficient information to make a judgment.A
agent_performance_feedbackstringThe feedback for the agent performance during the meetingThe agent took the initiative to inquire about and confirm the customer's needs, and provided clear instructions.
risk_factorstringThe risk_factor of the meetingCommunication difficulties
summarystringThe summary of the meetingThe customer needs to upload supplementary documents.
titlestringThe title(topic) of the meetingIssues with Customer Document Submission and Communication
transcriptList of Transcript object

Transcript object

nametypeDescriptionexample
textstringThe transcript textHi, I'm calling to ....
speakerstringThe speaker name of this transcripttest agent
Example of the request body
{
  "event_name": "dashboard_analysis_finished",
  "workspace_id": "xxx",
  "meeting_id": "xxx",
  "payload": {    
        "meeting_id": "ee48e21f-2576-49bc-9272-76960ae87a72",
        "customer_satisfaction_rating": "A",
        "agent_performance_rating": "A",
        "agent_performance_feedback": "The agent took the initiative to inquire about and confirm the customer's needs, and provided clear instructions.",
        "risk_factor": "Communication difficulties",
        "summary": "The customer needs to upload supplementary documents.",
        "title": "Issues with Customer Document Submission and Communication",
        "transcript": [
            {
                "text": "Hi, I'm calling to ....",
                "speaker": "test agent"
            }
         ]

  }
}

Example Python Script

Run below python script with command python3 import_meeting_audio.py --access-token $TOKEN --wav-path test.wav --wav-name test.wav --workspace-id $WORKSPACE_ID --seameet-url-base https://meet.seasalt.ai/seameet-api.

"""
It provides a command line interface to:
- create a meeting
- generate an upload URL for audio
- upload the audio
- start the transcription process.

Prerequisites:
- Python 3.8+
- pip install requests

Example usage:
    python import_meeting_audio.py --access-token eyxxx --workspace-id test --wav-path test.wav --wav-name test.wav
"""

import argparse
import logging
import sys
import time
import urllib.parse
from datetime import datetime, timezone
from typing import Optional

import requests

root = logging.getLogger()
root.setLevel("DEBUG")
handler = logging.StreamHandler(sys.stdout)
handler.setLevel("DEBUG")
formatter = logging.Formatter("%(asctime)s [%(name)s] %(levelname)-8s %(message)s")
handler.setFormatter(formatter)
root.addHandler(handler)


def main(args: argparse.Namespace):
    logging.debug("process start")
    meeting_id = _create_meeting(args)
    url = _get_meeting_upload_url(args, meeting_id)
    _upload_audio(args, url)
    _analyze_meeting_audio(args, meeting_id)

    logging.debug("process finished")


def _create_meeting(args: argparse.Namespace) -> str:
    body = {
        "meeting_name": args.meeting_name,
        "channel_type": "PHONE",
        "language": args.meeting_language,
        "start_time": args.meeting_start_time,
    }
    url = f"{args.seameet_url_base}/api/v1/workspaces/{args.workspace_id}/meetings"
    response = _query_backend_service(
        access_token=args.access_token,
        url=url,
        method="POST",
        body=body,
    )
    return response["id"]


def _get_meeting_upload_url(args: argparse.Namespace, meeting_id: str) -> str:
    body = {}
    url_parameters = {"file_name": args.wav_name}
    url = f"{args.seameet_url_base}/api/v1/workspaces/{args.workspace_id}/meetings/{meeting_id}/upload_audio_url"
    response = _query_backend_service(
        access_token=args.access_token,
        url=url,
        method="POST",
        body=body,
        url_parameters=url_parameters,
    )
    return response["upload_audio_url"]


def _upload_audio(args: argparse.Namespace, url: str):

    with open(args.wav_path, "rb") as f:
        response = requests.put(url, data=f)
        response.raise_for_status()

    logging.debug((f"uploaded {args.wav_path} to s3"))


def _analyze_meeting_audio(args: argparse.Namespace, meeting_id: str) -> str:
    body = {
        "meeting_id": meeting_id,
        "channel": 1,
        "audio_start_offset": args.audio_start_offset,
        "audio_format": args.audio_format,
        "audio_sample_rate": args.audio_sample_rate,
        "audio_encoding": args.audio_encoding,
        "scenario": args.scenario,
        "scenario_parameters": {
            "went_to_voicemail": False,
            "contains_recordings": False,
            "spoke_to_agent": False,
            "customer_number": args.customer_number,
            "customer_name": args.customer_name,
            "agent_name": args.agent_name,
            "enable_agent_recognition": args.enable_agent_recognition,
            "direction": args.direction,
        },
        "file_name": args.wav_name,
        "speaker_accounts": [],
        "diarization_options":"by_server",
        "num_speakers": 2,
        "enable_itn": True,
        "enable_punctuation": True,
        "use_existing_audio": args.use_existing_audio,
        "reset_meeting": args.reset_meeting,
        "queue_type": args.queue_type,
    }
    url = f"{args.seameet_url_base}/api/v1/workspaces/{args.workspace_id}/meetings/{meeting_id}/analyze_audio"
    _query_backend_service(
        access_token=args.access_token,
        url=url,
        method="POST",
        body=body,
    )


def _query_backend_service(
    access_token: str,
    url: str,
    method: str,
    body: dict = {},
    headers: dict = {},
    url_parameters: dict = {},
    timeout: Optional[float] = None,
) -> dict:
    start_time = time.time()
    response = None
    try:
        if url_parameters:
            url += "?" + urllib.parse.urlencode(url_parameters)
        final_headers = {
            "accept": r"application/json",
            "Content-Type": r"application/json",
            "Authorization": f"Bearer {access_token}",
        }

        if headers:
            final_headers.update(headers)
        # NOTE: Extend default timeout to wait the Backend API-Server responding.
        # - Especially the post_final_transcription is taking too long.
        session = requests.Session()
        request = requests.Request(method, url, json=body, headers=final_headers)
        response = session.send(request.prepare(), timeout=timeout)
        response.raise_for_status()
        if not response.text:
            return {}
        result_json = response.json()
        logging.debug(
            (
                f"finish a request to API server, time elapsed: {time.time()-start_time:.3f}s, method: {method}, url:{url}"
                f", method: {method}, body: {body}, response body: {result_json}"
            )
        )
        return result_json
    except Exception as e:
        logging.warning(
            (
                f"failed to request API server, time elapsed: {time.time()-start_time:.3f}s, method: {method}, url:{url}, "
                f"error: {e.__class__.__name__} {e} {response.text if response else ''}"
            )
        )
        raise e


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--workspace-id",
        dest="workspace_id",
        type=str,
        required=True,
        help="Set the workspace id.",
    )
    parser.add_argument(
        "--wav-path",
        dest="wav_path",
        type=str,
        required=True,
        help="Set the wav path.",
    )
    parser.add_argument(
        "--wav-name",
        dest="wav_name",
        type=str,
        required=True,
        help="Set the wav name.",
    )
    parser.add_argument(
        "--access-token",
        dest="access_token",
        type=str,
        required=True,
        help="The user's access token for the seameet api.",
    )
    parser.add_argument(
        "--meeting-name",
        dest="meeting_name",
        type=str,
        required=False,
        default="test meeting",
        help="Set the meeting name.",
    )
    parser.add_argument(
        "--meeting-language",
        dest="meeting_language",
        type=str,
        required=False,
        default="zh-TW",
        help="Set the meeting language.",
    )
    parser.add_argument(
        "--meeting-start-time",
        dest="meeting_start_time",
        type=str,
        required=False,
        default=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"),
        help="Set the meeting start time in the format of 'yyyy-mm-dd hh:mm:ss', UTC+0.",
    )
    parser.add_argument(
        "--seameet-url-base",
        dest="seameet_url_base",
        type=str,
        required=False,
        default="https://meet.seasalt.ai/seameet-api",
        help="the seameet url",
    )
    parser.add_argument(
        "--audio-start-offset",
        dest="audio_start_offset",
        type=int,
        required=False,
        default=0,
        help="indicate the audio start offset in seconds, relative to the start of the meeting.",
    )
    parser.add_argument(
        "--audio-format",
        dest="audio_format",
        type=str,
        required=False,
        default="wav",
        help="Set the audio format.",
    )
    parser.add_argument(
        "--audio-sample-rate",
        dest="audio_sample_rate",
        type=int,
        required=False,
        default=8000,
        help="Set the audio sample rate.",
    )
    parser.add_argument(
        "--audio-encoding",
        dest="audio_encoding",
        type=str,
        required=False,
        default="pcm_s8le",
        help="Set the audio encoding.",
    )
    parser.add_argument(
        "--scenario",
        dest="scenario",
        type=str,
        required=False,
        default="customer_service_call",
        help="Set the meeting scenario.",
    )
    parser.add_argument(
        "--customer-number",
        dest="customer_number",
        type=str,
        required=False,
        default="+886123456789",
        help="Set the customer number for the scenario: customer_service_call.",
    )
    parser.add_argument(
        "--customer-name",
        dest="customer_name",
        type=str,
        required=False,
        default="test customer",
        help="Set the customer name for the scenario: customer_service_call.",
    )
    parser.add_argument(
        "--agent-name",
        dest="agent_name",
        type=str,
        required=False,
        default="test agent",
        help="Set the agent name for the scenario: customer_service_call.",
    )
    parser.add_argument(
        "--direction",
        dest="direction",
        type=str,
        required=False,
        help="Set the meeting direction, INBOUND or OUTBOUND.",
    )
    parser.add_argument(
        "--enable-agent-recognition",
        dest="enable_agent_recognition",
        type=bool,
        required=False,
        default=True,
        help="enable_agent_recognition",
    )
    parser.add_argument(
        "--use-existing-audio",
        dest="use_existing_audio",
        type=bool,
        required=False,
        default=False,
        help="Use the meeting audio(all.wav) that already saved in seameet api.",
    )
    parser.add_argument(
        "--reset_meeting",
        dest="reset_meeting",
        type=bool,
        required=False,
        default=False,
        help="If it's true, it will delete all transcriptions and nlp things in the meeting before analyzing.",
    )
    parser.add_argument(
        "--queue_type",
        dest="queue_type",
        type=str,
        required=False,
        default="DEDICATED",
        help="The queue type=DEDICATED.",
    )

    args = parser.parse_args()
    main(args)
  1. If callback server implemented and set up complete by Seasalt.ai, get the analysis callback after a few minutes.
== header ==
host 865b-1-172-6-216.ngrok-free.app
user-agent Python/3.8 aiohttp/3.8.1
content-length 397
accept */*
accept-encoding gzip, deflate
content-type application/json
x-forwarded-for 54.70.236.205
x-forwarded-host 865b-1-172-6-216.ngrok-free.app
x-forwarded-proto https
x-seasalt-server-signature 3ec52b15632cbb634a900c7be551c60ea799b49f0a193a8e39cd1a844585cd3a
== body ==
{'event': 'dashboard_analysis_finished'
, payload: {'meeting_id': '2394a2dd-bc25-44f9-a159-643815e55d64', 'customer_satisfaction_rating': 'A', 'agent_performance_rating': 'A', 'agent_performance_feedback': 'The agent was professional and patient during the conversation with the customer, ensuring their needs were properly addressed.', "transcript":[...]
}}