Place your first call with the API

This guide shows how to trigger an outbound call with the demo voice API and follow its state. Everything is fictional: the call is simulated until a provider is configured.

Updated on

Before you start

  • A test key. In this guide: tq_test_EXEMPLE, a fictional value that opens no access.
  • A project. In this guide: prj_EXEMPLE_A (“Project A”).
  • Two phone numbers in E.164 format, without spaces. In this guide: +33199001234 (caller) and +33199005678 (callee), taken from a fictional range.
  • curl, or any HTTP client that can send headers.
Demo version. The API described here is a design proposal and may change. No production API is open today.

Start the call

  1. Generate a unique value for the Idempotency-Key header (a UUID). It is required on every POST request.
  2. Send POST /calls with from, to and project_id. Add flow_id if you want to attach a call flow.
  3. Keep the id from the response: you will use it to find the call in the log.
Fictional example: the key, numbers and identifiers are made up. The call is a simulation until a provider is configured.
curl -X POST https://api.example.test/v1/calls \
  -H "Authorization: Bearer tq_test_EXEMPLE" \
  -H "Idempotency-Key: 3f1c2a9e-5b7d-4e08-9a41-6d2b8c0e7f15" \
  -H "Content-Type: application/json" \
  -d '{"from":"+33199001234","to":"+33199005678","project_id":"prj_EXEMPLE_A"}'

Read the response

The API answers right away with the call it created. The ringing status means ringing was requested, not that anyone picked up. The simulated: true field is a reminder that no real communication was sent.

Fictional example response. Simulation: no real communication was sent.
{
  "id": "call_EXEMPLE_001",
  "status": "ringing",
  "simulated": true
}

Follow the call

The possible statuses are ringing, connected, completed and failed. Query the log with GET /calls to see how a call evolves, or subscribe to call.ringing, call.connected, call.completed and call.failed through a webhook.

The log separates talk time (duration_seconds) from billable time (billable_seconds). These are two different values. Do not confuse them with ringing time.

Fictional example: reading the log. The returned data is simulated.
curl "https://api.example.test/v1/calls?limit=5" \
  -H "Authorization: Bearer tq_test_EXEMPLE"

Common errors

SymptomLikely causeWhat to do
400 invalid_requestNumber with spaces or without the plus sign, missing field, missing Idempotency-Key.Send numbers in E.164 without spaces and add the Idempotency-Key header.
401 unauthorizedMissing or mistyped key, or a malformed Authorization header.Check the Bearer scheme and the key value.
403 forbiddenThe key has no access to the requested project.Use a key attached to the right project.
409 idempotency_conflictThe same idempotency key was used with a different request body.Generate a new key for a new operation. Reuse a key only to repeat the exact same request.
429 rate_limitedToo many requests in a short period.Wait for the time given by the Retry-After header before trying again.
failed statusThe call did not go through.The status does not give the cause. Do not guess it: check the call detail and the logs.

What this guide does not do

  • It places no real call: until a provider is configured, everything is simulated.
  • It does not guarantee that a call will connect. Capabilities depend on the country, the chosen provider and the contract.
  • It does not cover recording, transcription or advanced call commands (voice menu, conference), which depend on the provider.
  • One call can produce several usage lines depending on the contract. See the guide “Read your usage”.

Frequently asked questions

Can I replay the same request without creating two calls?

Yes, if you send the same Idempotency-Key with the same body. That is the purpose of the header: a double click or a network retry does not create a second call.

What is flow_id for?

It attaches the call to a call flow designed in the console. It is optional: without it, the call simply connects the two numbers.