Documentation
API reference
The Open Voice Shield REST API is served under /api on your platform host and authenticates with either a bearer token or an API key sent as X-API-Key. This page lists every customer-facing endpoint with its parameters, request and response shapes and the errors it raises.
Base URL and versioning#
Every path below is served under /api on your platform host, so GET /calls is GET https://your-ovs-host.example/api/calls. The interactive explorer is at /api/docs and the machine-readable schema at /api/openapi.json — that schema is what this page is generated from, so the two cannot disagree.
Requests and responses are JSON unless a row below says otherwise. Timestamps are UTC, ISO 8601. Identifiers are UUIDs. Lists take limit and offset and return a total, so you can page without losing rows.
Authentication#
There are two ways to authenticate, and they are interchangeable on every endpoint marked Bearer or API key:
- Bearer token
- Authorization: Bearer <access token>. You get one from POST /auth/login or POST /auth/signup. It is short-lived; a browser session renews it with POST /auth/refresh. Use this for a person at a screen.
- API key
- X-API-Key: <key>. It does not expire and is the right credential for a script, a switch integration or a scheduled job.
Create a key with POST /auth/api-keys as the account owner. The full key is in that one response and is stored only as a hash — it can never be shown again. Lose it and you mint a new one and revoke the old. A key acts as the user who minted it: revoke it with DELETE /auth/api-keys/{key_id}, or deactivate that user, and it stops working at once.
Owner-only endpoints
Anything that mints or revokes a credential, or that changes who can sign in, is owner-only. A member session answers 403 owner_required. Those rows are marked owner only in the Auth column.
Errors#
An error is a JSON body with a detail field and one of the status codes below. The Errors column on each endpoint lists only what that handler raises: 401 on a bad or missing credential and 422 on a malformed parameter apply everywhere and are not repeated row by row.
| Code | Means | What to do |
|---|---|---|
| 401 | Not authenticated | The token expired, the key is wrong or was revoked. Refresh or re-issue. |
| 403 | Forbidden | The credential is valid but not allowed here — a member on an owner-only route, or a suspended account. |
| 404 | Not found | No such record on your account. Another account's record is a 404, never a 403. |
| 409 | Conflict | The request contradicts what exists — a duplicate, or a state that does not allow it. |
| 422 | Validation error | A field is missing or out of range. The body names the field. |
| 429 | Too many requests | Back off. Retry-After carries the number of seconds. |
Authentication, sessions and keys#
Create an account, sign in, rotate a session and mint the API keys your own systems use. A key is minted by a signed-in owner and is shown once.
sign in, then mint a key — the key is shown once
API=https://your-ovs-host.example
TOKEN=$(curl -s -X POST $API/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"ops@acme.example","password":"correct-horse-battery"}' \
| sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')
curl -s -X POST $API/api/auth/api-keys \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"noc-integration"}'
# 201 {"id":"...","name":"noc-integration","prefix":"ovs_...","key":"ovs_...","revoked_at":null}
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /auth/api-keys | List the account keys, by prefix. The secret is not included. | Bearer or API key |
| POST | /auth/api-keys | Mint an API key. The full key is in the response and is never shown again. | Bearer or API key, owner only |
| DELETE | /auth/api-keys/{key_id} | Revoke a key immediately. | Bearer or API key, owner only |
| POST | /auth/change-password | Set a new password and end every other session. | Bearer or API key |
| GET | /auth/config | What the sign-in and sign-up screens need to know, before anyone signs in. | None |
| POST | /auth/login | Sign in with e-mail and password. Returns a token, or a second-factor challenge when a passkey is registered. | None |
| POST | /auth/login/passkey | Complete a two-factor sign-in by answering the passkey challenge from the password step. | None |
| POST | /auth/logout | End this browser session and clear its refresh cookie. | Refresh cookie + X-Requested-With |
| POST | /auth/logout-all | Sign out of every browser session at once. API keys keep working. | Bearer or API key |
| GET | /auth/me | The account behind the current credentials. | Bearer or API key |
| GET | /auth/passkeys | List the passkeys registered on the account. | Bearer or API key, owner only |
| DELETE | /auth/passkeys/{passkey_id} | Remove a passkey. Removing the last one turns two-factor sign-in off. | Bearer or API key, owner only |
| PATCH | /auth/passkeys/{passkey_id} | Rename a registered passkey. | Bearer or API key, owner only |
| POST | /auth/passkeys/register/begin | Start registering a passkey: returns the options the browser needs. | Bearer or API key, owner only |
| POST | /auth/passkeys/register/complete | Finish registering a passkey and turn on two-factor sign-in. | Bearer or API key, owner only |
| POST | /auth/refresh | Exchange the refresh cookie for a new access token and rotate the cookie. | Refresh cookie + X-Requested-With |
| POST | /auth/signup | Create an account and return a first access token. | None |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /auth/api-keys | — | — | 200 ApiKeyOut[] | — |
| POST /auth/api-keys | — | name string, required | 201 ApiKeyCreated | 403 owner_required |
| DELETE /auth/api-keys/{key_id} | key_id uuid, required | — | 204 No content | 403 owner_required 404 API key not found |
| POST /auth/change-password | — | current_password string, required new_password string, required |
204 No content | 400 invalid_current_password 422 new_password must differ from the current password |
| GET /auth/config | — | — | 200 AuthConfigOut | — |
| POST /auth/login | — | email email, required password string, required |
200 TokenResponse, or TwoFactorRequired when a passkey is registered | 401 Invalid email or password 403 Account suspended 429 Too many requests |
| POST /auth/login/passkey | — | login_token string, required assertion object, required |
200 TokenResponse | 401 invalid_login |
| POST /auth/logout | — | — | 204 No content | — |
| POST /auth/logout-all | — | — | 204 No content | — |
| GET /auth/me | — | — | 200 CustomerOut | — |
| GET /auth/passkeys | — | — | 200 PasskeyOut[] | 403 owner_required |
| DELETE /auth/passkeys/{passkey_id} | passkey_id uuid, required | — | 204 No content | 403 owner_required 404 Passkey not found |
| PATCH /auth/passkeys/{passkey_id} | passkey_id uuid, required | name string, required | 200 PasskeyOut | 403 owner_required 404 Passkey not found |
| POST /auth/passkeys/register/begin | — | — | 200 PasskeyRegisterBeginOut | 403 owner_required |
| POST /auth/passkeys/register/complete | — | credential object, required state string, required name string or null |
201 PasskeyOut | 400 Bad request 403 owner_required 409 passkey_already_registered |
| POST /auth/refresh | — | — | 200 TokenResponse | 401 Not authenticated |
| POST /auth/signup | — | email email, required password string, required company string or null |
201 SignupResponse | 403 Signup is disabled 409 Email already registered 429 Too many requests |
Users on your account#
Every person who signs in to your account has a user row. Owners invite, rename and deactivate; members can read the list.
invite a member (owner only)
curl -s -X POST $API/api/customer/users \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"email":"analyst@acme.example","name":"Night shift"}'
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /customer/users | List the people who can sign in to the account, owner first. | Bearer or API key |
| POST | /customer/users | Invite a member. They receive a temporary password and must change it on first sign-in. | Bearer or API key, owner only |
| PATCH | /customer/users/{user_id} | Rename, deactivate or reactivate a member. The owner cannot be deactivated. | Bearer or API key, owner only |
| POST | /customer/users/{user_id}/resend-invite | Issue a new temporary password and re-send the invitation. The old one stops working. | Bearer or API key, owner only |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /customer/users | — | — | 200 CustomerUserList | — |
| POST /customer/users | — | email email, required name string or null |
201 CustomerUserInvited | 403 owner_required 409 Email already registered |
| PATCH /customer/users/{user_id} | user_id uuid, required | name string or null is_active boolean or null |
200 CustomerUserOut | 400 cannot_deactivate_owner 403 owner_required 404 User not found |
| POST /customer/users/{user_id}/resend-invite | user_id uuid, required | — | 200 CustomerUserInvited | 400 cannot_reset_owner 403 owner_required 404 User not found |
Trunk, whitelist, destinations and routing#
The connection itself: the address your switch sends to, the source addresses allowed to send, where a call goes next, and the prefix rules that choose between destinations.
whitelist the address your switch sends from
curl -s $API/api/customer/network-info -H "X-API-Key: $OVS_KEY"
curl -s -X POST $API/api/customer/ips \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"cidr":"203.0.113.7/32","label":"Toronto SBC"}'
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /customer/destinations | Where analyzed calls are handed on to. | Bearer or API key |
| POST | /customer/destinations | Add a destination — the SBC, PBX or carrier the call was already going to. | Bearer or API key |
| DELETE | /customer/destinations/{dest_id} | Remove a destination. | Bearer or API key |
| PATCH | /customer/destinations/{dest_id} | Change a destination, or make it the default. | Bearer or API key |
| GET | /customer/ips | The source addresses allowed to send you traffic. | Bearer or API key |
| POST | /customer/ips | Whitelist a source address or range. Traffic from anywhere else is rejected. | Bearer or API key |
| DELETE | /customer/ips/{ip_id} | Remove a whitelisted address. | Bearer or API key |
| GET | /customer/network-info | The host, port and transports your switch sends the INVITE to. | Bearer or API key |
| GET | /customer/routing-rules | The prefix rules that choose a destination. | Bearer or API key |
| POST | /customer/routing-rules | Route a dialled prefix to a specific destination. | Bearer or API key |
| DELETE | /customer/routing-rules/{rule_id} | Remove a prefix rule. | Bearer or API key |
| PATCH | /customer/routing-rules/{rule_id} | Change a prefix rule, its priority or its destination. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /customer/destinations | — | — | 200 DestinationOut[] | — |
| POST /customer/destinations | — | host string, required port integer, default 5060 transport "udp" | "tcp" | "tls", default "udp" is_default boolean, default false label string or null kind "sip" | "voice_ai", default "sip" provider string or null agent_id string or null config object or null tech_prefix string or null |
201 DestinationOut | 409 Maximum number of destinations reached |
| DELETE /customer/destinations/{dest_id} | dest_id uuid, required | — | 204 No content | 404 Destination not found |
| PATCH /customer/destinations/{dest_id} | dest_id uuid, required | host string or null port integer or null transport "udp" | "tcp" | "tls" or null is_default boolean or null label string or null kind "sip" | "voice_ai" or null provider string or null agent_id string or null config object or null tech_prefix string or null |
200 DestinationOut | 404 Destination not found |
| GET /customer/ips | — | — | 200 IpOut[] | — |
| POST /customer/ips | — | cidr string, required label string or null destination_id uuid or null enabled boolean, default true |
201 IpOut | 404 Destination not found 409 CIDR already whitelisted 422 Validation error 503 Whitelist busy, retry |
| DELETE /customer/ips/{ip_id} | ip_id uuid, required | — | 204 No content | 404 IP entry not found |
| GET /customer/network-info | — | — | 200 NetworkInfoOut | — |
| GET /customer/routing-rules | — | — | 200 RoutingRuleOut[] | — |
| POST /customer/routing-rules | — | prefix string, required destination_id uuid, required enabled boolean, default true priority integer, default 100 label string or null |
201 RoutingRuleOut | 404 Destination not found 409 Conflict |
| DELETE /customer/routing-rules/{rule_id} | rule_id uuid, required | — | 204 No content | 404 Routing rule not found |
| PATCH /customer/routing-rules/{rule_id} | rule_id uuid, required | prefix string or null destination_id uuid or null enabled boolean or null priority integer or null label string or null |
200 RoutingRuleOut | 404 Destination not found 409 Conflict |
Calls and analysis#
Every call that traversed the platform, its verdict, its transcript, its recording, its SIP flow and a self-contained evidence bundle.
the high-risk calls of the last day, then one verdict
curl -s "$API/api/calls?min_probability=70&limit=20" -H "X-API-Key: $OVS_KEY"
curl -s $API/api/calls/$CALL_ID/analysis -H "X-API-Key: $OVS_KEY"
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /calls | Search your calls by time, status, verdict or your own reference. | Bearer or API key |
| GET | /calls/{call_id} | One call: numbers, timing, where it was routed and its verdict. | Bearer or API key |
| GET | /calls/{call_id}/analysis | The verdict on its own: probability, category, red flags and recommendation. | Bearer or API key |
| GET | /calls/{call_id}/export | Download a self-contained evidence bundle for the call — it opens offline, with no account. | Bearer or API key |
| GET | /calls/{call_id}/pcap | Download the media capture of the call. | Bearer or API key |
| GET | /calls/{call_id}/recording | Download the call audio as a stereo WAV. | Bearer or API key |
| GET | /calls/{call_id}/sip-log | The SIP message flow of the call, as rows and as a plain-text log. | Bearer or API key |
| GET | /calls/{call_id}/transcript | The transcript of the call, with its language and confidence. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /calls | status string or null analysis_status string or null from timestamp or null to timestamp or null min_probability integer or null, 0–100 external_id string or null limit integer, default 50, 1–500 offset integer, default 0 |
— | 200 CallList | 422 Validation error |
| GET /calls/{call_id} | call_id uuid, required | — | 200 CallDetail | 404 Call not found |
| GET /calls/{call_id}/analysis | call_id uuid, required | — | 200 AnalysisOut | 404 Call not found |
| GET /calls/{call_id}/export | call_id uuid, required | — | 200 application/zip — the evidence bundle | 404 Call not found 429 too_many_exports |
| GET /calls/{call_id}/pcap | call_id uuid, required | — | 200 The capture file, or a zip when the call had several media legs | 404 Call not found |
| GET /calls/{call_id}/recording | call_id uuid, required | — | 200 audio/wav — the file, or a redirect to a short-lived download URL | 404 Call not found |
| GET /calls/{call_id}/sip-log | call_id uuid, required | — | 200 SipLogOut | 404 Call not found |
| GET /calls/{call_id}/transcript | call_id uuid, required | — | 200 TranscriptOut | 404 Call not found |
Sharing a call outside your account#
A password-protected link to one call, for a carrier or a customer who has no account. The owner side is authenticated; the reader side is not.
share one call, then open it as the reader would
curl -s -X POST $API/api/calls/$CALL_ID/share \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"expires_in_hours":72,"label":"carrier dispute"}'
# 201 — "password" is in this response and in no other
curl -s -X POST $API/api/public/shares/$TOKEN/unlock \
-H 'Content-Type: application/json' -d '{"password":"..."}'
curl -s $API/api/public/shares/$TOKEN -H "X-Share-Token: $VIEW_TOKEN"
| Method | Path | Does | Auth |
|---|---|---|---|
| POST | /calls/{call_id}/share | Create a password-protected public link to one call. The password is returned once. | Bearer or API key |
| GET | /calls/{call_id}/shares | The links that exist for this call. Passwords are never included. | Bearer or API key |
| DELETE | /calls/shares/{share_id} | Revoke a link. It stops opening immediately. | Bearer or API key |
| POST | /calls/shares/{share_id}/rotate | Issue a new password for the same link, returned once. | Bearer or API key |
| GET | /public/shares/{token} | The shared call, once unlocked. | View token |
| GET | /public/shares/{token}/meta | Whether a link is real and still live, and who shared it. Nothing about the call. | None |
| GET | /public/shares/{token}/recording | The shared call audio, once unlocked. | View token |
| POST | /public/shares/{token}/unlock | Exchange the link password for a short-lived view token. | None |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| POST /calls/{call_id}/share | call_id uuid, required | expires_in_hours integer or null label string or null |
201 CallShareCreated | 404 Call not found |
| GET /calls/{call_id}/shares | call_id uuid, required | — | 200 CallShareList | 404 Call not found |
| DELETE /calls/shares/{share_id} | share_id uuid, required | — | 200 CallShareOut | 404 Share link not found |
| POST /calls/shares/{share_id}/rotate | share_id uuid, required | — | 200 CallShareCreated | 404 Share link not found 409 This link is revoked or expired |
| GET /public/shares/{token} | token string, required t string or null |
— | 200 PublicSharePayload | 401 Invalid link or password 404 This link is no longer available |
| GET /public/shares/{token}/meta | token string, required | — | 200 ShareMetaOut | — |
| GET /public/shares/{token}/recording | token string, required t string or null |
— | 200 audio/wav — the file, or a redirect to a short-lived download URL | 401 Invalid link or password 404 This link is no longer available |
| POST /public/shares/{token}/unlock | token string, required | password string, required | 200 ShareUnlockOut | 401 Invalid link or password 429 too_many_attempts |
Cases#
The investigation record attached to a call: title, severity, status, assignee and a comment thread.
open a case on a call and comment on it
CASE=$(curl -s -X POST $API/api/cases \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"title":"Wangiri from +1 555","severity":"high","call_id":"'$CALL_ID'"}')
curl -s -X POST $API/api/cases/$CASE_ID/comments \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"body":"Carrier notified."}'
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /cases | Search cases by status, severity or assignee. | Bearer or API key |
| POST | /cases | Open a case, optionally attached to a call. | Bearer or API key |
| GET | /cases/{case_id} | One case, with its comment thread. | Bearer or API key |
| PATCH | /cases/{case_id} | Change status, severity, text or assignee. The new assignee is notified. | Bearer or API key |
| POST | /cases/{case_id}/comments | Add a comment to a case. | Bearer or API key |
| GET | /cases/prefill | Suggested title, severity and description for a case about a given call. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /cases | status string or null severity string or null assigned_to uuid or null call_id uuid or null limit integer, default 50, 1–200 offset integer, default 0 |
— | 200 CaseList | 422 Validation error |
| POST /cases | — | title string, required description string or null severity "low" | "medium" | "high" | "critical", default "medium" call_id uuid or null |
201 CaseOut | 404 Call not found 409 case_already_exists_for_call |
| GET /cases/{case_id} | case_id uuid, required | — | 200 CaseDetail | 404 Case not found |
| PATCH /cases/{case_id} | case_id uuid, required | title string or null description string or null status "open" | "in_review" | "resolved" | "dismissed" or null severity "low" | "medium" | "high" | "critical" or null assigned_to uuid or null clear_assigned_to boolean, default false |
200 CaseOut | 404 Case not found 422 assigned_to must be an active user of this account |
| POST /cases/{case_id}/comments | case_id uuid, required | body string, required | 201 CaseCommentOut | 404 Case not found |
| GET /cases/prefill | call_id uuid, required | — | 200 JSON object: title, severity, description, existing_case_id | 404 Call not found |
Automation and controlled numbers#
Rules that act on a verdict without a human — block or divert a number for a set time — and the table of numbers currently under control.
block a number for 24 hours when the verdict is 90 or above
curl -s -X POST $API/api/automation/rules \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"name":"auto-block","min_probability":90,"action":"block","duration_hours":24}'
curl -s $API/api/automation/controls -H "X-API-Key: $OVS_KEY"
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /automation/controls | The numbers currently blocked or diverted by a rule. | Bearer or API key |
| POST | /automation/controls/{control_id}/release | Release a controlled number so it is treated normally again. | Bearer or API key |
| GET | /automation/rules | The automation rules on the account. | Bearer or API key |
| POST | /automation/rules | Add a rule that blocks or diverts a number when a verdict crosses a threshold. | Bearer or API key |
| DELETE | /automation/rules/{rule_id} | Remove a rule. | Bearer or API key |
| PATCH | /automation/rules/{rule_id} | Change a rule, or turn it off. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /automation/controls | include_released boolean, default false limit integer, default 50, 1–500 offset integer, default 0 |
— | 200 AniControlList | — |
| POST /automation/controls/{control_id}/release | control_id uuid, required | — | 200 AniControlOut | 404 control not found 409 control already released |
| GET /automation/rules | — | — | 200 AutomationRuleOut[] | — |
| POST /automation/rules | — | name string, required enabled boolean, default true min_probability integer, default 90 recommendations string[] or null, default ["block"] action "block" | "divert", default "block" divert_destination_id uuid or null duration_hours integer or null |
201 AutomationRuleOut | 404 divert destination not found 409 Maximum number of automation rules reached |
| DELETE /automation/rules/{rule_id} | rule_id uuid, required | — | 204 No content | 404 automation rule not found |
| PATCH /automation/rules/{rule_id} | rule_id uuid, required | name string or null enabled boolean or null min_probability integer or null recommendations string[] or null action "block" | "divert" or null divert_destination_id uuid or null duration_hours integer or null clear_duration boolean, default false |
200 AutomationRuleOut | 404 divert destination not found 422 divert_destination_id is required when action is 'divert' |
Alerts and webhooks#
Push a verdict out: e-mail alert rules with their own thresholds, and one signed HTTP webhook for your own systems.
point a webhook at your own system and test it
curl -s -X PUT $API/api/customer/webhook \
-H "X-API-Key: $OVS_KEY" -H 'Content-Type: application/json' \
-d '{"url":"https://noc.acme.example/hooks/ovs","secret":"a-long-random-string"}'
curl -s -X POST $API/api/customer/webhook/test -H "X-API-Key: $OVS_KEY"
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /customer/alert-rules | The e-mail alert rules on the account. | Bearer or API key |
| POST | /customer/alert-rules | Alert named recipients when a verdict crosses a threshold. | Bearer or API key |
| DELETE | /customer/alert-rules/{rule_id} | Remove an alert rule. | Bearer or API key |
| PATCH | /customer/alert-rules/{rule_id} | Change an alert rule, or turn it off. | Bearer or API key |
| POST | /customer/alert-rules/{rule_id}/test | Send a sample alert to the rule recipients now. | Bearer or API key |
| GET | /customer/webhook | The webhook URL configured for the account. | Bearer or API key |
| PUT | /customer/webhook | Set or clear the webhook URL and its signing secret. | Bearer or API key |
| POST | /customer/webhook/test | Deliver one signed test event now and report what the endpoint answered. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /customer/alert-rules | — | — | 200 AlertRuleOut[] | — |
| POST /customer/alert-rules | — | name string, required enabled boolean, default true min_probability integer, default 70 categories string[] or null recommendations string[] or null recipients string[] or null throttle_minutes integer, default 0 include_transcript boolean, default false |
201 AlertRuleOut | 409 Maximum number of alert rules reached |
| DELETE /customer/alert-rules/{rule_id} | rule_id uuid, required | — | 204 No content | 404 alert rule not found |
| PATCH /customer/alert-rules/{rule_id} | rule_id uuid, required | name string or null enabled boolean or null min_probability integer or null categories string[] or null recommendations string[] or null recipients string[] or null throttle_minutes integer or null include_transcript boolean or null |
200 AlertRuleOut | 404 alert rule not found |
| POST /customer/alert-rules/{rule_id}/test | rule_id uuid, required | — | 200 AlertRuleTestOut | 404 alert rule not found 409 smtp_not_configured |
| GET /customer/webhook | — | — | 200 WebhookOut | — |
| PUT /customer/webhook | — | url string or null secret string or null |
200 WebhookOut | — |
| POST /customer/webhook/test | — | — | 200 WebhookTestOut | — |
Plans, balance and payments#
What the plans are, what you are on, what you have spent and how to add credit or subscribe by card.
what the plans cost, and what is left
curl -s $API/api/plans
curl -s $API/api/customer/balance -H "X-API-Key: $OVS_KEY"
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /customer/balance | Current credit, plan and the minutes left in the cycle. | Bearer or API key |
| GET | /customer/ledger | Every credit and debit on the account, newest first. | Bearer or API key |
| POST | /customer/payments/checkout | Start a one-off top-up and return the URL to send the browser to. | Bearer or API key |
| GET | /customer/payments/config | Whether card payment is enabled, and the presets the billing page offers. | Bearer or API key |
| POST | /customer/payments/subscribe | Start a card subscription to a plan and return the URL to send the browser to. | Bearer or API key |
| POST | /customer/plan | Move the account to another plan. | Bearer or API key |
| GET | /plans | The plans on offer, with their prices and included minutes. | None |
| POST | /webhooks/stripe | Payment-provider callback. Credits a top-up and renews a plan cycle. Not called by you. | Provider signature |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /customer/balance | — | — | 200 BalanceOut | — |
| GET /customer/ledger | limit integer, default 50, 1–500 offset integer, default 0 |
— | 200 LedgerList | — |
| POST /customer/payments/checkout | — | amount number or string, required | 200 CheckoutSessionOut | 409 Conflict 502 Payment provider error |
| GET /customer/payments/config | — | — | 200 PaymentsPublicConfig | — |
| POST /customer/payments/subscribe | — | plan_code string, required | 200 CheckoutSessionOut | 400 Pay-as-you-go has no monthly fee — nothing to subscribe to 404 Plan not found 409 Conflict 502 Payment provider error |
| POST /customer/plan | — | plan_code string, required | 200 CustomerOut | 402 Insufficient balance for the first month's fee 404 Plan not found 409 Already subscribed to this plan |
| GET /plans | — | — | 200 PlanOut[] | — |
| POST /webhooks/stripe | — | — | 200 JSON object acknowledging the event | 400 Invalid signature 409 Conflict |
Dashboard, statistics and live calls#
Aggregates for a dashboard, and the calls that are in progress right now.
a week of activity, and what is on the wire now
curl -s "$API/api/customer/dashboard?days=7" -H "X-API-Key: $OVS_KEY"
curl -s $API/api/customer/live-calls -H "X-API-Key: $OVS_KEY"
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /customer/dashboard | Calls, minutes, spend and risk distribution over the last N days. | Bearer or API key |
| GET | /customer/live-calls | Calls in progress right now, with elapsed time and the credit countdown. | Bearer or API key |
| GET | /customer/stats | Headline counters for the account. | Bearer or API key |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /customer/dashboard | days integer, default 30, 1–366 | — | 200 CustomerDashboardOut | — |
| GET /customer/live-calls | — | — | 200 LiveCallsOut | — |
| GET /customer/stats | from timestamp or null to timestamp or null |
— | 200 StatsOut | — |
Service health#
One unauthenticated endpoint to poll from your own monitoring.
poll from your monitoring
curl -s $API/api/health
# {"status":"ok",...}
| Method | Path | Does | Auth |
|---|---|---|---|
| GET | /health | Liveness of the service. No credentials needed. | None |
| Endpoint | Path and query | Request body | Returns | Errors |
|---|---|---|---|---|
| GET /health | — | — | 200 HealthOut | — |
Objects#
Every object named above, with its fields as the API returns and accepts them. A field marked or null can be absent.
| Field | Type | Required |
|---|---|---|
| name | string | yes |
| enabled | boolean | default true |
| min_probability | integer | default 70 |
| categories | string[] or null | no |
| recommendations | string[] or null | no |
| recipients | string[] or null | no |
| throttle_minutes | integer | default 0 |
| include_transcript | boolean | default false |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| name | string | yes |
| enabled | boolean | yes |
| min_probability | integer | yes |
| categories | string[] or null | yes |
| recommendations | string[] or null | yes |
| recipients | string[] or null | yes |
| throttle_minutes | integer | yes |
| include_transcript | boolean | yes |
| created_at | timestamp | yes |
| updated_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| sent | boolean | yes |
| error | string or null | no |
| latency_ms | integer | yes |
| recipients | string[] | yes |
| Field | Type | Required |
|---|---|---|
| name | string or null | no |
| enabled | boolean or null | no |
| min_probability | integer or null | no |
| categories | string[] or null | no |
| recommendations | string[] or null | no |
| recipients | string[] or null | no |
| throttle_minutes | integer or null | no |
| include_transcript | boolean or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| provider | string or null | no |
| model | string or null | no |
| location | string or null | no |
| prompt_version | string | yes |
| title | string or null | yes |
| probability | integer | yes |
| category | string | yes |
| entity | string or null | yes |
| caller_identity | string or null | yes |
| red_flags | string[] or null | yes |
| language | string or null | yes |
| tcpa_comment | string or null | yes |
| summary | string or null | yes |
| recommendation | string | yes |
| keywords | string[] or null | yes |
| input_tokens | integer | yes |
| output_tokens | integer | yes |
| cost | number | yes |
| latency_ms | integer | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| title | string or null | yes |
| probability | integer | yes |
| category | string | yes |
| recommendation | string | yes |
| red_flags | string[] or null | yes |
| Field | Type | Required |
|---|---|---|
| total | integer | yes |
| limit | integer | yes |
| offset | integer | yes |
| items | AniControlOut[] | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| ani | string | yes |
| action | string | yes |
| divert_destination_id | uuid or null | yes |
| reason | string or null | yes |
| expires_at | timestamp or null | yes |
| released_at | timestamp or null | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| name | string | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| name | string | yes |
| prefix | string | yes |
| last_used_at | timestamp or null | yes |
| revoked_at | timestamp or null | yes |
| created_at | timestamp | yes |
| key | string | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| name | string | yes |
| prefix | string | yes |
| last_used_at | timestamp or null | yes |
| revoked_at | timestamp or null | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| signup_enabled | boolean | yes |
| password_min_length | integer | default 12 |
| access_token_ttl_sec | integer | yes |
| Field | Type | Required |
|---|---|---|
| name | string | yes |
| enabled | boolean | default true |
| min_probability | integer | default 90 |
| recommendations | string[] or null | default ["block"] |
| action | "block" | "divert" | default "block" |
| divert_destination_id | uuid or null | no |
| duration_hours | integer or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| name | string | yes |
| enabled | boolean | yes |
| min_probability | integer | yes |
| recommendations | string[] or null | yes |
| action | string | yes |
| divert_destination_id | uuid or null | yes |
| duration_hours | integer or null | yes |
| created_at | timestamp | yes |
| updated_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| name | string or null | no |
| enabled | boolean or null | no |
| min_probability | integer or null | no |
| recommendations | string[] or null | no |
| action | "block" | "divert" or null | no |
| divert_destination_id | uuid or null | no |
| duration_hours | integer or null | no |
| clear_duration | boolean | default false |
| Field | Type | Required |
|---|---|---|
| balance | number | yes |
| plan | string | yes |
| plan_name | string | yes |
| ports | integer | yes |
| active_calls | integer | yes |
| cycle_minutes_used | number | yes |
| included_minutes | integer or null | yes |
| per_minute_rate | number | yes |
| plan_renews_at | timestamp or null | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| sip_call_id | string | yes |
| customer_id | uuid | yes |
| src_ip | string | yes |
| ani | string or null | yes |
| dialed | string or null | yes |
| dest_host | string | yes |
| dest_port | integer | yes |
| dest_transport | string | yes |
| media_ip | string or null | yes |
| external_id | string or null | no |
| external_name | string or null | no |
| routed_destination_id | uuid or null | no |
| route_prefix | string or null | no |
| dest_kind | string | default "sip" |
| dest_tech_prefix | string or null | no |
| direction | string | yes |
| status | string | yes |
| sip_code | integer or null | yes |
| end_reason | string or null | yes |
| started_at | timestamp | yes |
| answered_at | timestamp or null | yes |
| ended_at | timestamp or null | yes |
| duration_sec | integer or null | yes |
| billsec | integer or null | yes |
| charged_amount | number | yes |
| rate_applied | number or null | yes |
| recording_wav_path | string or null | yes |
| transcript_status | string | yes |
| analysis_status | string | yes |
| processing_error | string or null | yes |
| created_at | timestamp | yes |
| analysis | AnalysisOut or null | no |
| recording_pcap_paths | string[] or null | yes |
| captured_headers | object or null | no |
| case_id | uuid or null | no |
| routed_to_label | string or null | no |
| transcript | TranscriptMeta or null | no |
| transcript_summary | string or null | no |
| Field | Type | Required |
|---|---|---|
| total | integer | yes |
| limit | integer | yes |
| offset | integer | yes |
| items | CallOut[] | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| sip_call_id | string | yes |
| customer_id | uuid | yes |
| src_ip | string | yes |
| ani | string or null | yes |
| dialed | string or null | yes |
| dest_host | string | yes |
| dest_port | integer | yes |
| dest_transport | string | yes |
| media_ip | string or null | yes |
| external_id | string or null | no |
| external_name | string or null | no |
| routed_destination_id | uuid or null | no |
| route_prefix | string or null | no |
| dest_kind | string | default "sip" |
| dest_tech_prefix | string or null | no |
| direction | string | yes |
| status | string | yes |
| sip_code | integer or null | yes |
| end_reason | string or null | yes |
| started_at | timestamp | yes |
| answered_at | timestamp or null | yes |
| ended_at | timestamp or null | yes |
| duration_sec | integer or null | yes |
| billsec | integer or null | yes |
| charged_amount | number | yes |
| rate_applied | number or null | yes |
| recording_wav_path | string or null | yes |
| transcript_status | string | yes |
| analysis_status | string | yes |
| processing_error | string or null | yes |
| created_at | timestamp | yes |
| analysis | AnalysisSummary or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| call_id | uuid | yes |
| url | string | yes |
| label | string or null | yes |
| created_by | string or null | yes |
| created_at | timestamp | yes |
| expires_at | timestamp or null | yes |
| revoked_at | timestamp or null | yes |
| view_count | integer | yes |
| last_viewed_at | timestamp or null | yes |
| active | boolean | yes |
| password | string | yes |
| Field | Type | Required |
|---|---|---|
| items | CallShareOut[] | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| call_id | uuid | yes |
| url | string | yes |
| label | string or null | yes |
| created_by | string or null | yes |
| created_at | timestamp | yes |
| expires_at | timestamp or null | yes |
| revoked_at | timestamp or null | yes |
| view_count | integer | yes |
| last_viewed_at | timestamp or null | yes |
| active | boolean | yes |
| Field | Type | Required |
|---|---|---|
| date | string | yes |
| calls | integer | yes |
| high_risk | integer | yes |
| Field | Type | Required |
|---|---|---|
| body | string | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| author_kind | string | yes |
| author_label | string or null | yes |
| body | string | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| title | string | yes |
| description | string or null | no |
| severity | "low" | "medium" | "high" | "critical" | default "medium" |
| call_id | uuid or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| case_no | integer | yes |
| customer_id | uuid | yes |
| call_id | uuid or null | yes |
| title | string | yes |
| description | string or null | yes |
| status | string | yes |
| severity | string | yes |
| created_by | string or null | yes |
| assigned_to | uuid or null | yes |
| created_at | timestamp | yes |
| updated_at | timestamp | yes |
| assigned_to_label | string or null | no |
| comment_count | integer | default 0 |
| comments | CaseCommentOut[] | default [] |
| call | CallOut or null | no |
| Field | Type | Required |
|---|---|---|
| total | integer | yes |
| limit | integer | yes |
| offset | integer | yes |
| items | CaseOut[] | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| case_no | integer | yes |
| customer_id | uuid | yes |
| call_id | uuid or null | yes |
| title | string | yes |
| description | string or null | yes |
| status | string | yes |
| severity | string | yes |
| created_by | string or null | yes |
| assigned_to | uuid or null | yes |
| created_at | timestamp | yes |
| updated_at | timestamp | yes |
| assigned_to_label | string or null | no |
| comment_count | integer | default 0 |
| Field | Type | Required |
|---|---|---|
| title | string or null | no |
| description | string or null | no |
| status | "open" | "in_review" | "resolved" | "dismissed" or null | no |
| severity | "low" | "medium" | "high" | "critical" or null | no |
| assigned_to | uuid or null | no |
| clear_assigned_to | boolean | default false |
| Field | Type | Required |
|---|---|---|
| current_password | string | yes |
| new_password | string | yes |
| Field | Type | Required |
|---|---|---|
| amount | number or string | yes |
| Field | Type | Required |
|---|---|---|
| session_id | string | yes |
| url | string | yes |
| Field | Type | Required |
|---|---|---|
| days | integer | yes |
| from | timestamp | yes |
| to | timestamp | yes |
| calls_today | integer | yes |
| calls_period | integer | yes |
| minutes_period | number | yes |
| spend_period | number | yes |
| high_risk_pct | number | yes |
| risk_distribution | RiskBucket[] | yes |
| calls_per_day | CallsPerDay[] | yes |
| recent_high_risk | CallOut[] | yes |
| balance | number | yes |
| plan | DashboardPlan | yes |
| cycle_minutes_used | number | yes |
| active_calls | integer | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| string | yes | |
| company | string or null | yes |
| role | string | yes |
| status | string | yes |
| must_change_password | boolean | default false |
| balance | number | yes |
| plan_code | string | yes |
| ports | integer | yes |
| plan_started_at | timestamp or null | yes |
| plan_renews_at | timestamp or null | yes |
| cycle_minutes_used | number | yes |
| webhook_url | string or null | yes |
| created_at | timestamp | yes |
| twofa_enabled | boolean | default false |
| impersonated_by | string or null | no |
| pilot | PilotStatus or null | no |
| Field | Type | Required |
|---|---|---|
| yes | ||
| name | string or null | no |
| Field | Type | Required |
|---|---|---|
| user | CustomerUserOut | yes |
| welcome_email | WelcomeEmailStatus or null | no |
| Field | Type | Required |
|---|---|---|
| items | CustomerUserOut[] | yes |
| max_users | integer | default 10 |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| string | yes | |
| name | string or null | yes |
| role | string | yes |
| is_active | boolean | yes |
| must_change_password | boolean | default false |
| last_login_at | timestamp or null | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| name | string or null | no |
| is_active | boolean or null | no |
| Field | Type | Required |
|---|---|---|
| code | string | yes |
| name | string | yes |
| ports | integer | yes |
| included_minutes | integer or null | yes |
| renews_at | timestamp or null | yes |
| Field | Type | Required |
|---|---|---|
| host | string | yes |
| port | integer | default 5060 |
| transport | "udp" | "tcp" | "tls" | default "udp" |
| is_default | boolean | default false |
| label | string or null | no |
| kind | "sip" | "voice_ai" | default "sip" |
| provider | string or null | no |
| agent_id | string or null | no |
| config | object or null | no |
| tech_prefix | string or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| host | string | yes |
| port | integer | yes |
| transport | string | yes |
| is_default | boolean | yes |
| label | string or null | yes |
| kind | string | yes |
| provider | string or null | yes |
| agent_id | string or null | yes |
| config | object or null | yes |
| tech_prefix | string or null | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| host | string or null | no |
| port | integer or null | no |
| transport | "udp" | "tcp" | "tls" or null | no |
| is_default | boolean or null | no |
| label | string or null | no |
| kind | "sip" | "voice_ai" or null | no |
| provider | string or null | no |
| agent_id | string or null | no |
| config | object or null | no |
| tech_prefix | string or null | no |
| Field | Type | Required |
|---|---|---|
| status | string | yes |
| db | boolean | yes |
| version | string | yes |
| Field | Type | Required |
|---|---|---|
| cidr | string | yes |
| label | string or null | no |
| destination_id | uuid or null | no |
| enabled | boolean | default true |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| cidr | string | yes |
| label | string or null | yes |
| destination_id | uuid or null | yes |
| enabled | boolean | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| total | integer | yes |
| limit | integer | yes |
| offset | integer | yes |
| items | LedgerOut[] | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| type | string | yes |
| amount | number | yes |
| balance_after | number | yes |
| call_id | uuid or null | yes |
| description | string or null | yes |
| waived_amount | number | default 0 |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| status | string | yes |
| ani | string or null | yes |
| dialed | string or null | yes |
| external_id | string or null | yes |
| external_name | string or null | yes |
| dest_host | string | yes |
| dest_port | integer | yes |
| dest_transport | string | yes |
| dest_kind | string | yes |
| route_prefix | string or null | yes |
| media_node | string or null | yes |
| started_at | timestamp | yes |
| answered_at | timestamp or null | yes |
| elapsed_sec | integer | yes |
| max_call_seconds | integer or null | yes |
| remaining_sec | integer or null | yes |
| Field | Type | Required |
|---|---|---|
| items | LiveCall[] | yes |
| active_count | integer | yes |
| ports | integer | yes |
| ports_in_use | integer | yes |
| Field | Type | Required |
|---|---|---|
| yes | ||
| password | string | yes |
| Field | Type | Required |
|---|---|---|
| ingress_host | string | yes |
| ingress_port | integer | default 5060 |
| transports | string[] | default ["udp","tcp"] |
| Field | Type | Required |
|---|---|---|
| login_token | string | yes |
| assertion | object | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| name | string | yes |
| transports | string[] or null | no |
| created_at | timestamp | yes |
| last_used_at | timestamp or null | yes |
| Field | Type | Required |
|---|---|---|
| options | object | yes |
| state | string | yes |
| Field | Type | Required |
|---|---|---|
| credential | object | yes |
| state | string | yes |
| name | string or null | no |
| Field | Type | Required |
|---|---|---|
| name | string | yes |
| Field | Type | Required |
|---|---|---|
| enabled | boolean | yes |
| publishable_key | string | yes |
| currency | string | yes |
| preset_amounts | integer[] | default [25,50,100,250] |
| min_custom_amount | integer | default 10 |
| Field | Type | Required |
|---|---|---|
| active | boolean | default false |
| started_at | timestamp or null | no |
| ends_at | timestamp or null | no |
| days_left | integer | default 0 |
| minutes_limit | integer or null | no |
| minutes_used | number | default 0 |
| exhausted | boolean | default false |
| waived_total | number | default 0 |
| Field | Type | Required |
|---|---|---|
| plan_code | string | yes |
| Field | Type | Required |
|---|---|---|
| code | string | yes |
| name | string | yes |
| monthly_fee | number | yes |
| ports | integer | yes |
| included_minutes | integer or null | yes |
| per_minute_rate | number | yes |
| min_billable_seconds | integer | yes |
| active | boolean | yes |
| description | string or null | yes |
| Field | Type | Required |
|---|---|---|
| title | string or null | no |
| probability | integer or null | no |
| category | string or null | no |
| entity | string or null | no |
| red_flags | string[] or null | no |
| tcpa_comment | string or null | no |
| summary | string or null | no |
| recommendation | string or null | no |
| Field | Type | Required |
|---|---|---|
| dialed | string or null | no |
| ani | string or null | no |
| direction | string or null | no |
| started_at | timestamp or null | no |
| duration_sec | integer or null | no |
| Field | Type | Required |
|---|---|---|
| shared_by | string or null | no |
| shared_at | timestamp or null | no |
| label | string or null | no |
| expires_at | timestamp or null | no |
| call | PublicShareCall | yes |
| analysis | PublicShareAnalysis or null | no |
| transcript | PublicShareTranscript or null | no |
| has_recording | boolean | default false |
| Field | Type | Required |
|---|---|---|
| text | string | default "" |
| segments | object[] or null | no |
| Field | Type | Required |
|---|---|---|
| bucket | "0-29" | "30-69" | "70-100" | yes |
| count | integer | yes |
| Field | Type | Required |
|---|---|---|
| prefix | string | yes |
| destination_id | uuid | yes |
| enabled | boolean | default true |
| priority | integer | default 100 |
| label | string or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| prefix | string | yes |
| destination_id | uuid | yes |
| enabled | boolean | yes |
| priority | integer | yes |
| label | string or null | yes |
| created_at | timestamp | yes |
| updated_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| prefix | string or null | no |
| destination_id | uuid or null | no |
| enabled | boolean or null | no |
| priority | integer or null | no |
| label | string or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| string | yes | |
| company | string or null | yes |
| role | string | yes |
| must_change_password | boolean | default false |
| status | string | yes |
| Field | Type | Required |
|---|---|---|
| expires_in_hours | integer or null | no |
| label | string or null | no |
| Field | Type | Required |
|---|---|---|
| exists | boolean | yes |
| requires_password | boolean | default true |
| revoked | boolean | default false |
| expired | boolean | default false |
| company_name | string or null | no |
| Field | Type | Required |
|---|---|---|
| view_token | string | yes |
| expires_in | integer | yes |
| Field | Type | Required |
|---|---|---|
| password | string | yes |
| Field | Type | Required |
|---|---|---|
| yes | ||
| password | string | yes |
| company | string or null | no |
| Field | Type | Required |
|---|---|---|
| customer | CustomerOut | yes |
| access_token | string | yes |
| token_type | string | default "bearer" |
| expires_in | integer | yes |
| Field | Type | Required |
|---|---|---|
| time_stamp | timestamp | yes |
| direction | string | yes |
| method | string | yes |
| status | string or null | no |
| fromip | string | yes |
| toip | string | yes |
| fromtag | string or null | no |
| totag | string or null | no |
| first_line | string | yes |
| headers | object or null | no |
| Field | Type | Required |
|---|---|---|
| call_id | uuid | yes |
| sip_call_id | string | yes |
| messages | SipLogMessage[] | yes |
| text | string | yes |
| Field | Type | Required |
|---|---|---|
| from | timestamp or null | no |
| to | timestamp or null | no |
| calls | integer | yes |
| answered_calls | integer | yes |
| minutes | number | yes |
| spend | number | yes |
| by_category | object | yes |
| by_recommendation | object | yes |
| avg_probability | number or null | yes |
| Field | Type | Required |
|---|---|---|
| access_token | string | yes |
| token_type | string | default "bearer" |
| expires_in | integer | yes |
| customer | SessionCustomer or null | no |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| provider | string or null | no |
| model | string or null | no |
| location | string or null | no |
| language | string or null | yes |
| audio_seconds | number or null | yes |
| cost | number | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| id | uuid | yes |
| provider | string or null | no |
| model | string or null | no |
| location | string or null | no |
| language | string or null | yes |
| text | string | yes |
| segments | object[] or null | yes |
| audio_seconds | number or null | yes |
| cost | number | yes |
| created_at | timestamp | yes |
| Field | Type | Required |
|---|---|---|
| url | string or null | yes |
| secret_set | boolean | yes |
| Field | Type | Required |
|---|---|---|
| delivered | boolean | yes |
| status_code | integer or null | no |
| error | string or null | no |
| latency_ms | integer | yes |
| Field | Type | Required |
|---|---|---|
| url | string or null | no |
| secret | string or null | no |
| Field | Type | Required |
|---|---|---|
| sent | boolean | default false |
| error | string or null | no |
| skipped_reason | string or null | no |
Generated from the platform's own API schema on 2026-08-27: 81 operations over 66 paths, and 87 objects. Operator-only endpoints are not part of this reference and never appear here.