Voice API
Voice over WebRTC
Start an outbound browser call and receive a URL that can be opened by your WebRTC client
These features are experimental. If you face any issues, please contact support.
WebRTC is the browser-based calling option. Your server creates the call room with the API, then opens the returned room URL in your web application. The URL contains the call session and is intended to be used by a browser-based voice or video client.
All requests in this document use the Conversation API base URL:
https://a.loopmessage.com/api/v1/voice/
The API key must be sent in the Authorization header. Bearer and Basic prefixes are accepted, but the plain API key is also supported.
Check sender availability
Use this endpoint before starting a call when you want to verify that a sender can be used for voice calls.
POST https://a.loopmessage.com/api/v1/voice/line-availability/
Headers
| Name | Type | Description |
|---|---|---|
| Authorization* | String | Organization API key. |
| Content-Type* | String | application/json. |
Request body
| Name | Type | Description |
|---|---|---|
| sender* | String | A sender name or sender ID belonging to your organization. |
{
"sender": "your_sender_id"
}
Response
Response {.tabset .tabset-fade}
tab 200: Sender availability
{
"available": true,
"sender": "sender id"
}
tab 400: Invalid sender
{
"success": false,
"code": 220,
"message": "Invalid or unable to use this sender name"
}
Start an outbound WebRTC call
Create a call session for a phone number or iMessage email address. The recipient must be a valid contact and must be eligible for an outbound conversation under your organization settings.
POST https://a.loopmessage.com/api/v1/voice/init/
Request body
| Name | Type | Description |
|---|---|---|
| contact* | String | Recipient phone number or iMessage email address. Phone numbers may be supplied in international format (with country code). |
| type | String | Optional. Call type. Possible values: audio or video. Default value: audio. |
| sender* | String | Sender ID. Use this to select a sender explicitly. By default will be used fist value from your |
| pool | String | Optional. sender pool UUID. Do not send pool together with a sender field. |
{
"contact": "+13235550123",
"type": "audio",
"sender": "+13235550100"
}
If no sender is supplied, the API selects an eligible sender from the recent conversation or from the organization sender pool. To start a conversation with a new recipient, the selected sender must allow first outbound conversations.
Response
Response {.tabset .tabset-fade}
tab 200: Call created
{
"contact": "+13235550123",
"message_id": "message/call ID",
"organization": "organization ID",
"sender": "sender ID",
"type": "audio",
"url": "https://voice.example.com/..."
}
Open the returned url in the browser client used by your application. Keep message_id as the call’s API identifier for your own records and webhook correlation.
tab 400: Request failed
{
"success": false,
"code": 150,
"message": "No 'contact' parameter in request"
}
Common failures include an invalid recipient, an unavailable sender, an opted-out contact, a sender that cannot initiate a new conversation, or an invalid type value.
Video calls knowing issues
Currently, FaceTime video calls have two issues:
- They can experience lag in video broadcasting. We’re working on reducing this latency.
- The video quality is low. At present, this is the quality level that FaceTime is able to stream via WebRTC, and we strive to transmit it without further compression. In the future, we hope Apple can raise its minimum video quality to 720p.
Handle an inbound call
Inbound calls are delivered through webhooks. To receive them, open Webhook Settings in the dashboard and enable Inbound call.
The inbound flow has two webhook events:
inbound_call_initasks your server whether it should accept the call.inbound_callis sent after the call is accepted and contains the WebRTC room URL.
1. Accept or reject the incoming call
When an incoming call starts, your webhook endpoint receives a inbound_call_ringing webhook with the following JSON payload:
{
"event": "inbound_call_ringing",
"contact": "+13231112233",
"sender_id": "string",
"sender": "+13235550100",
"service": "facetime"
}
This is a non-retryable webhook. Your endpoint must return HTTP 200 within 5 seconds to accept the call. A timeout, a network error, or any response status other than 200 rejects the call.
The response body is not used to establish the call. Return a successful HTTP response as soon as your application has decided to accept it.
2. Open the call URL
After your endpoint accepts the initialization webhook, a second inbound_call webhook is sent within a few seconds:
{
"message_id": "string",
"url": "https://voice.example.com/..."
"contact": "+13231112233",
"event": "inbound_call",
"webhook_id": "string"
}
Open the webhook url in your WebRTC client immediately. The caller has already been told that the call was accepted, so your application should join the room as quickly as possible. The url contains the room and inbound direction required for the browser client to join the active call.
This is a non-retryable webhook. Your endpoint must return HTTP 200 within 5 seconds, the call will be rejected.
Inbound call sequence
- The caller starts a call to one of your active senders.
- Your webhook endpoint receives the
inbound_call_initpayload. - Your endpoint returns HTTP
200within 5 seconds to accept the call, or returns any other status to reject it. - Your webhook endpoint receives the
inbound_callpayload with the roomurl. - Your application opens the URL and joins the call.
- The caller and your WebRTC user are connected in the active FaceTime call.
Browser integration
The API call should be made by your backend so the organization API key is not exposed in browser source code. Return the url to the browser only after the API responds successfully.
- Your backend sends POST /voice/init/.
- Your backend returns call “url” to the browser.
- Your WebRTC client opens the URL and requests microphone or/and camera permission.
- Your application tracks the call using message_id and configured callbacks.