Developer Calls API
Start supported NovaSynth Phone or LiveKit tests from scripts and CI, poll their status, and export or replay a redacted call configuration.
The Developer Calls API runs a NovaSynth test without pre-registering a project, persona, scenario, or connection in the dashboard. Send the endpoint credentials and test definition with each request, then poll the returned status URL until the call finishes.
Runtime execution currently supports Phone and LiveKit endpoints in Voice mode only. This applies both to credentials supplied inline and to a saved connection referenced by ID. A request with "mode": "text" returns 400, and a webhook value returns 501 because webhook delivery is not supported; poll statusUrl instead. Use a dashboard batch in Text mode for HTTP Chat.
Calls land in a Developer API project by default. Pass an optional projectId to run them in an existing project of the API key's organization.
Endpoint support
| Endpoint type | Inline request | Existing connection | Current result |
|---|---|---|---|
| Phone | Supported | Supported | Test is queued |
| LiveKit | Supported | Supported | Test is queued |
| HTTP Chat | Not accepted | Not supported | An existing connection returns 501 Not Implemented |
| WebSocket, Pipecat, VAPI, Retell, ElevenLabs Conversational AI | Request shape recognized, but not supported | Not supported | Returns 501 Not Implemented before dispatch |
The request validator recognizes the additional inline credential shapes, but a separate runtime gate rejects them before dispatch. Accepting their request shape is not execution support. See the connection support matrix for dashboard batches, persistent endpoint records, direction, and provider webhooks.
Authentication and base URL
Create an organization-scoped API key in the Noveum dashboard and send it as a bearer token:
export NOVEUM_API_KEY="replace-with-your-key"
export NOVEUM_API_BASE="https://api.noveum.ai/api"Do not put provider secrets or the Noveum API key in source control. Noveum stores a redacted configuration snapshot for each test so you can export its setup without exposing credentials.
Start one phone test
curl --fail-with-body --silent --show-error \
--request POST "$NOVEUM_API_BASE/v1/developer/calls" \
--header "Authorization: Bearer $NOVEUM_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"endpoint": {
"type": "phone",
"phoneNumber": "+14155550123",
"phoneCountryCode": "+1"
},
"persona": {
"name": "Frustrated subscriber",
"goal": "Cancel a renewal without accepting an upsell",
"tonePreference": "frustrated"
},
"scenario": {
"name": "Cancellation policy",
"description": "Ask to cancel, challenge one retention offer, then confirm the cancellation."
},
"mode": "voice",
"maxCallDurationS": 180,
"serviceVersion": "checkout-agent-2026-07-30"
}'Phone numbers must be valid E.164 values and must begin with the supplied dial prefix. A successful request returns 202 Accepted with a callId, batchId, statusUrl, and estimated credit and USD cost.
The inline persona accepts the same fields as a saved persona, including primaryLanguage and ttsVoiceModel. Leave ttsVoiceModel unset to let NovaSynth choose a TTS model that supports the persona's spoken languages. The inline scenario accepts planned interruptions as described in Scenarios. Set "eval": false to run the call without evaluation.
Start one LiveKit test
Use the same endpoint with an inline LiveKit connection:
{
"endpoint": {
"type": "livekit",
"livekitUrl": "wss://your-project.livekit.cloud",
"livekitApiKey": "your-livekit-key",
"livekitApiSecret": "your-livekit-secret",
"livekitAgentName": "support-agent"
},
"persona": {
"name": "New customer",
"goal": "Ask whether the plan supports two team members"
},
"scenario": {
"name": "Plan question",
"description": "Ask about the entry plan and verify the seat limit."
},
"mode": "voice",
"maxCallDurationS": 180
}The API accepts an existing NovaSynth connection through { "type": "existing", "endpointId": "..." } as well, but the connection must belong to the API key's organization and its type must currently be Phone or LiveKit. Other saved connection types return 501 Not Implemented.
Poll the result
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $NOVEUM_API_KEY" \
"$NOVEUM_API_BASE/v1/developer/calls/$CALL_ID"Poll about every three seconds until status is completed, failed, or cancelled. The result can include:
- duration and normalized transcript turns;
- a temporary recording URL and its expiration time;
- evaluation status, score, pass/fail result, summary, and scorer results;
- an error and completion timestamp.
Use the returned recordingUrlExpiresAt value rather than persisting the signed recording URL.
Batch tests
POST /v1/developer/calls/batch accepts a shared endpoint and up to 100 persona/scenario pairs in calls. Set concurrencyLimit from 1 to 20; it defaults to 5. The response includes the batch ID, call IDs, total call count, status URL, and estimated total cost.
Poll GET /v1/developer/calls/batch/:id for completed and failed counts, pass rate, average score, and the status of each call.
Inbound calls
Set "direction": "inbound" to test an outbound bot: Noveum reserves one of its numbers for the synthetic persona, and your bot dials it. Inbound calls need a Phone endpoint. A saved Phone connection must also be configured for inbound calls.
runId, claimUrl, and an inbound statusUrl under /v1/novasynth/inbound/runs/{runId}.statusUrl until status is ready. The response then includes phoneNumber, dialWindowClosesAt, profile, personaName, and scenarioName.phoneNumber before dialWindowClosesAt, passing profile to it as it would a real customer's details.resultsUrl after the call completes.When no number is free, the status is waiting with reason set to no_number_available and a retryAfterMs hint; retry claimUrl for the same run. If arming fails after the call was created, the response says so and includes resultsUrl and claimUrl. Inspect the call instead of creating it again.
An inbound batch runs one call at a time and arms only its first call. The batch response includes an inbound object for that call and a claimNextUrl. Finish the first call, then POST to claimNextUrl to arm the next one, and poll each returned run until it is ready. See Inbound calls for a ready-made dialling loop.
Export and replay configurations
Calls created through this API retain a redacted configuration snapshot:
| Endpoint | Purpose |
|---|---|
GET /v1/developer/calls/:id/config | Export one call as JSON |
GET /v1/developer/calls/:id/config?format=curl | Export a cURL example |
GET /v1/developer/calls/:id/config?format=python | Export a polling Python script that also handles inbound claiming |
GET /v1/developer/calls/batch/:id/config | Export a whole batch configuration |
POST /v1/developer/calls/:id/replay | Replay when the stored snapshot still contains usable credentials |
Secret fields are replaced with placeholders in stored snapshots. In the normal case, export the configuration, restore secrets from your secret manager, and submit it as a new call. A direct replay returns an error when the redacted snapshot cannot pass validation.
Operational checks
- Estimate the call count and duration before a CI run; quota is checked before the tests start.
- Use
serviceVersionto associate results with a deployment or commit. - Set a client timeout for the create request, then use polling rather than holding the connection open.
- Record
callIdandbatchIdin CI output, but never print endpoint credentials.
Related
- NovaSynth setup - configure persistent connections in the dashboard
- Personas and scenarios - build reusable test inputs
- Run tests and review results - launch and review persistent dashboard batches
- API and agent access - use the same organization API key with Noveum’s MCP server