prod - 20261103-155809 - acd260dde964f9fc12a4ec4d79828e2feffa7ef1

Voice-to-voice

Architecture

The integration consists of an HTTP setup phase followed by a real-time WebSocket phase.

sequenceDiagram
    participant Caller
    participant Seamly
    participant Client

    Caller->>Seamly: calls
    Seamly->>Client: POST /api/conversations
    Client-->>Seamly: 201 + WebSocket URL

    Seamly->>Client: open WebSocket

    Client->>Seamly: { "type": "audio", ... }
    Seamly->>Caller: plays audio fragment

    Caller->>Seamly: speaks
    Seamly->>Client: { "type": "audio", ... }

    Caller->>Seamly: hangs up
    Seamly->>Client: { "type": "hangup" }

Integration flow

Call start

When an incoming call is routed to your integration, Seamly sends an authenticated request to your conversation endpoint before the conversation starts.

POST /api/conversations
Content-Type: application/json
X-Seamly-Signature: <HMAC signature>

Request body

{
  "project_id": "c8dc0d63-19be-479e-b89c-c99276b7e023",
  "channel_name": "voice",
  "phone_number": "+31881111111",
  "environment": {
    "from_phone_anonymous": false,
    "from_phone_number": "+31612345678"
  }
}
Property Type Required Description
project_id string Yes UUID of the Seamly project. Use this to identify the relevant tenant or configuration in your system.
channel_name string Yes Name of the Seamly channel through which the call arrived. This is normally voice .
phone_number string Yes Dialled number in international E.164 format.
environment object Yes Information about the caller and call environment. Additional properties may be added in the future.
environment.from_phone_anonymous boolean Yes Whether the caller withheld their telephone number.
environment.from_phone_number string or null Yes Caller's telephone number in E.164 format, or null when unavailable.

The request schema permits additional properties at the top level and inside environment . Your implementation should ignore unknown properties rather than reject the request.

Successful response

Return HTTP 201 Created with a JSON body that configures the conversation.

{
  "type": "audio",
  "_links": {
    "socket": {
      "href": "wss://api.acme.com/conversations/client-conversation-7f31a4/websocket"
    }
  }
}

Response properties

Property Type Required Description
type string Yes Either audio or text. For a text integration see our Text-to-voice .
_links.socket.href URI Yes Secure WebSocket URL Seamly must connect to for this conversation.

The response schema does not allow unknown top-level properties or unknown properties inside the defined nested objects.

Error responses

The specification defines the following error responses:

  • 401 Unauthorized when request authentication fails.
  • 500 Internal Server Error when your application cannot create or configure the conversation.

Return errors in this format:

{
  "error": "Human-readable error message"
}

Accept the WebSocket connection

After validating the HTTP response, Seamly connects to the URL in _links.socket.href using a secure WebSocket connection. Just as with the initial POST request an X-Seamly-Signature header is sent.

All messages are JSON objects with a type property.

Exchange audio messages

As soon as the WebSocket is established, both parties may start to send Audio messages.

{
  "type": "audio",
  "payload": {
    "variables": {
      "audio": "...... Base64 encoded 8 KHz 16bit mono PCM .....",
      "id": "99ee8529-4edd-455d-a1ca-b1466048d67f"
    }
  }
}

End a call

Client-initiated hang-up

To instruct Seamly to end the call, send:

{ 
  "type": "hangup",
  "payload": {
    "direction": "inbound",
    "sipHeaders": {}
  }
}

In a bit Seamly will close the WebSocket.

Call transfer

Transferring a call is not available yet. Do not use it until Seamly confirms support.

Caller-initiated hang-up

When the caller has ended the call by hanging up the telephone, Seamly sends:

{ 
  "type": "hangup",
  "payload": {
    "direction": "outbound"
  }
}

Report errors

Either side may send an error event:

{
  "type": "error",
  "payload": {
    "reason": "validation_error",
    "description": "Unexpected field in message",
    "sipStatusCode": 486
  }
}
Property Description
reason Stable, machine-readable, atom-like error reason.
description Human-readable explanation suitable for diagnostics.
sipStatusCode SIP response status code associated with the error, when available

Error handling

Seamly reports WebSocket protocol errors to your application. Seamly will not reconnect in case of an unexpected WebSocket connection failure. In this case the call ends without an error message being spoken to the caller.

Conversation setup failures

Your HTTP endpoint must return 201 Created with a valid conversation configuration. HTTP failures, invalid JSON or response fields prevent Seamly from starting the conversation. Your WebSocket URL must use wss:// .

Seamly cannot currently report these setup failures back to you through the Voice API. Setup also fails if Seamly cannot establish the initial WebSocket connection. The reconnection behaviour below applies only after a WebSocket connection has been established.

WebSocket protocol errors

If your application sends a JSON message that fails validation or violates the expected message sequence, Seamly responds with an error message.

Seamly only logs error messages sent by your application. Sending an error does not trigger recovery, end the call or produce speech for the caller. To explain a failure to the caller while the connection is available, send audio using the normal messages. You can then send hangup to end the call.

WebSocket event reference

Events sent by Seamly to your application

Event Purpose
audio Audio of the caller or of the Client.
play_done Stop the playback of the current Audio. In case the passed ID matches the current Audio the playback is stopped and a PlayDone message is returned. When the ID does not match an Error message is returned.
dtmf_key_press A DTMF key was pressed
hangup Hangup of the caller or of the Client.
dial_succeeded The outbound call was dialled successfully
error Inform the other party an error has occurred.

Events sent by your application to Seamly

Event Purpose
audio Audio of the caller or of the Client.
kill_audio Stop the playback of the current Audio. In case the passed ID matches the current Audio the playback is stopped and a PlayDone message is returned. When the ID does not match an Error message is returned.
hangup Hangup of the caller or of the Client.
refer Refer the call
dial ial another participant into the call
error Inform the other party an error has occurred.

Security recommendations

  • Verify the X-Seamly-Signature before processing a conversation requests.
  • Compare signatures using a constant-time comparison function.
  • Reject malformed JSON and invalid message sequences.

Specification files

This guide describes the behaviour defined by:

  • OpenAPI — HTTP conversation creation and configuration.
  • AsyncAPI — WebSocket connection for an audio-based integration.

Treat the machine-readable specifications as the authoritative schema definitions. This guide explains how to combine them into a working integration and highlights operational details that must be agreed with Seamly during onboarding.f