Use PlaceCall to place a voice call, give the agent a task, and read what happened. This guide asks a business what time it closes today.
Before you start
You need a PlaceCall API key with available credits, a terminal with curl and Python 3, and a US phone number you own or are authorized to call. Get an API key if you do not have one, then set it as PLACECALL_API_KEY in your terminal or server environment. Keep it out of browser code and public repositories. See Authentication for key setup.
Submitting the request with a valid number places a real outbound call and can use credits. The +1XXXXXXXXXX placeholder below cannot be dialed; replace it with the authorized number in E.164 format.
1. Describe the task
Give the agent one clear objective in brief: what to ask, any information it needs, and when to finish. For this example, it should ask for today’s closing time, thank the person, and end the call.
| Field | What to send |
|---|---|
target_phone | The authorized US number, including the +1 country code. |
brief | The instructions the agent should follow during the call. |
language | en for this English-language example. |
2. Place the call
Create a unique request ID once for this intended call. This command uses Python 3 to generate one:
CALL_REQUEST_ID=$(python3 -c 'import uuid; print(uuid.uuid4())')
Send the request, including that ID in the Idempotency-Key header:
curl --include --request POST https://api.voygr.tech/calls \
--header "X-API-Key: $PLACECALL_API_KEY" \
--header "Idempotency-Key: $CALL_REQUEST_ID" \
--header "Content-Type: application/json" \
--data '{
"target_phone": "+1XXXXXXXXXX",
"brief": "Ask what time the business closes today. Thank them and end the call.",
"language": "en"
}'
--include shows the HTTP status alongside the response. For the freeform request above, save the returned call ID:
| HTTP status | Where to find the ID | What it means |
|---|---|---|
201 Created | call.call_id | The call was created. |
202 Accepted | call_id | The call is queued and waiting to start. |
Structured calls (intent + slots) instead return top-level call_id for both 201 and 202. If your application supports both request shapes, extract the ID from the parsed JSON as response.get("call", response)["call_id"] in Python.
Both responses mean the request was accepted. Use the returned ID to follow progress; do not submit another call just because this one is queued.
If the connection drops before you receive a response, retry the same POST with the same request ID and unchanged body. Do not rerun the ID-generation command for that retry. A replay returns the stored response with Idempotent-Replayed: true. Use a new ID only when you intend to place another call; reusing an ID with a different body returns 409.
3. Follow progress
Set CALL_ID to the ID returned in step 2, then look up the call:
CALL_ID="REPLACE_WITH_RETURNED_CALL_ID"
curl "https://api.voygr.tech/calls/$CALL_ID" \
--header "X-API-Key: $PLACECALL_API_KEY"
This response contains the call fields directly, so read status, not call.status. Repeat the GET while the call is in progress. A queued call uses this same lookup.
The call has finished when status is completed, failed, or cancelled. If a completed call still has a null outcome_type, check again: its outcome can be available shortly after the call ends.
4. Read the outcome
| Field | What it tells you |
|---|---|
status | Whether the call is still running or has ended. |
outcome_type | The classified result of the conversation. |
outcome_summary | A short explanation of what happened. |
transcript_full | The conversation transcript, when available. |
For the closing-time task, read the summary and transcript for the business’s answer. completed means the call ended; it does not by itself mean the agent obtained the information you wanted. Handle missing results in your application rather than treating them as an answer.
Understand outcome values
status tracks the call lifecycle; outcome_type explains the result. These are the currently produced outcome values:
| Outcome | Meaning |
|---|---|
success_booked | A booking was confirmed. |
success_refused | The business answered but declined the request. |
success_no_booking | A conversation completed without a booking, including information requests. |
failed_no_answer | Nobody answered. |
failed_voicemail | The call reached voicemail. |
failed_busy | The line was busy. |
failed_short_hangup | The call ended before a substantive conversation. |
failed_technical | A technical failure prevented completion. |
failed_no_agent_available | No person answered within the hold-time limit. |
failed_no_disclosure | The required AI/recording disclosure could not be delivered. |
failed_call_dropped | The connection dropped during the conversation. |
failed_wrong_number | The number did not reach the intended business. |
failed_cancelled | The customer cancelled the call. |
failed_no_engagement | The person answered but did not engage with the task. |
failed_agent_mute | The agent failed to speak when required. |
A refusal is different from a technical failure: the business may decline even though the call reached it successfully. Preserve unfamiliar outcome values for troubleshooting rather than discarding the entire response.
Receive live events
For live updates and mid-call questions, create the call with ask_user_mode: "stream" and consume its event stream incrementally:
curl --no-buffer "https://api.voygr.tech/calls/$CALL_ID/events?after_event_id=0" \
--header "X-API-Key: $PLACECALL_API_KEY"
Parse each SSE event as it arrives; do not wait for the whole response to finish. Ignore heartbeat events and SSE comments, preserving the last event ID when a heartbeat has no id. After a disconnect while the call is active, reconnect with after_event_id set to the last received id. The Last-Event-ID header is not supported. Answer ask_user events promptly through the answer endpoint.
Handle errors and retries
Read the error response before retrying:
| HTTP status | What to check |
|---|---|
401 | The API key is missing or invalid. |
402 | The key does not have enough credits to place the call. |
403 | The key cannot use this calling operation. |
404 on lookup | Check the call ID and use the same API key that created it. |
409 | Check the error: the concurrent-call limit may be reached, or the idempotency key may have been reused with a different request. |
422 | Check the phone number and request fields, including brief. |
429 | Wait before retrying; follow Retry-After when returned. |
503 | The service is temporarily unavailable; follow any retry guidance in the response. |
For an uncertain POST response, keep the same request ID and body as described above. For access help, contact support@voygr.tech.
See Place a call for the full request and response reference, including its interactive playground.
On this page
