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.
Start the call
- Generate a unique value for the Idempotency-Key header (a UUID). It is required on every POST request.
- Send POST /calls with from, to and project_id. Add flow_id if you want to attach a call flow.
- Keep the id from the response: you will use it to find the call in the log.
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.
{
"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.
curl "https://api.example.test/v1/calls?limit=5" \
-H "Authorization: Bearer tq_test_EXEMPLE"Common errors
| Symptom | Likely cause | What to do |
|---|---|---|
| 400 invalid_request | Number 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 unauthorized | Missing or mistyped key, or a malformed Authorization header. | Check the Bearer scheme and the key value. |
| 403 forbidden | The key has no access to the requested project. | Use a key attached to the right project. |
| 409 idempotency_conflict | The 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_limited | Too many requests in a short period. | Wait for the time given by the Retry-After header before trying again. |
| failed status | The 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.