Call Troubleshooting

This guide helps you diagnose and resolve common call issues. Each problem includes symptoms, causes, and solutions.

Note

AI Implementation Hint

When troubleshooting, always start by fetching the call details: GET /v1/calls/{call-id}. The status, hangup_by, hangup_reason, and timestamp fields provide the primary diagnostic information. If the call has an associated flow_id, also check GET /v1/activeflows/{activeflow-id} for flow execution errors.

Debugging Tools

Before troubleshooting, understand the tools available:

API Endpoints for Debugging:

Get call details:
GET /v1/calls/{call-id}

Get activeflow status:
GET /v1/activeflows/{activeflow-id}

Get recordings (use recording_ids from the call object):
GET /v1/recordings/{recording-id}

List all recordings:
GET /v1/recordings

Note

AI Implementation Hint

The call-id is a UUID returned when creating a call via POST /v1/calls or from webhook events. The activeflow-id is obtained from the call’s activeflow_id field. The recording-id is obtained from the call’s recording_ids array. All debugging endpoints require a valid authentication token (JWT or access key).

WebSocket for Real-time Monitoring:

Connect:
wss://api.voipbin.net/v1.0/ws?token=<token>

Subscribe to all call events:
{
    "type": "subscribe",
    "topics": ["customer_id:<your-id>:call:*"]
}

Events you'll receive:
- call_created
- call_ringing
- call_answered (progressing)
- call_hungup
- call_recording_started
- call_transcribing

Call Never Connects

Symptom: Call status goes directly from dialing to hangup. The hangup_reason is failed. No ringing ever occurred (tm_ringing is 9999-01-01 00:00:00.000000).

Diagnostic API call:

GET /v1/calls/{call-id}

Look for:
{
  "status": "hangup",
  "hangup_reason": "failed",
  "hangup_by": "remote",
  "tm_ringing": "9999-01-01 00:00:00.000000"
}

Cause 1: Invalid Phone Number Format

Problem:
"+1 555-123-4567" (has spaces/dashes)

Fix:
"+15551234567" (E.164 format, digits only after +)

Cause 2: Number Not Provisioned or Invalid Type

Problem:
Source number not in your account, or is a virtual number.

Diagnostic:
GET /v1/numbers
Verify the source number appears in the response with:
- type: "normal" (not "virtual")
- status: "active"

Fix:
Purchase a number via POST /v1/numbers or use a normal,
active number you already own. Virtual numbers cannot be
used as the source for outgoing PSTN calls.

If the source fails validation, VoIPBIN falls back to the
OutboundConfig's ``default_outgoing_source_number_id``. If
that field is not set (uuid.Nil), the call is rejected.

To configure the default outgoing source number, update
your OutboundConfig:
PUT https://api.voipbin.net/v1.0/outbound_config
{ "default_outgoing_source_number_id": "<number-uuid>" }

Cause 3: Insufficient Balance

Problem:
Account balance too low for call.

Diagnostic:
GET /v1/billing-accounts
Check that balance > 0 and status = "active".

Fix:
Add funds to your account.

Cause 4: Carrier Rejection

Problem:
Destination carrier rejected the call.

Symptoms:
- Works to some numbers, not others
- Specific area codes fail

Fix:
Contact support with the call-id for investigation.
Try alternate routes if available.

Source Number / Caller ID Issues

Symptom: Outgoing PSTN call shows “Anonymous” caller ID, or shows a different number than the one provided in source.target.

Diagnostic API call:

GET /v1/calls/{call-id}

Check the source field in the response:
{
  "source": {
    "type": "tel",
    "target": "anonymous",
    "target_name": "Anonymous"
  }
}

If target is "anonymous", the call leg used anonymous caller ID
(e.g., a non-PSTN leg that skipped source validation, or a PSTN
call from before the OutboundConfig migration). For new PSTN calls
with no valid source and no OutboundConfig default, the call is
now rejected instead.

Cause 1: Source Number Not in E.164 Format

Problem:
Source does not start with "+" (e.g., "15551234567").

Fix:
Always use E.164 format: "+15551234567".

Cause 2: Source is a Virtual Number

Problem:
Source number exists in your account but has type "virtual".
Only "normal" type numbers can be used as source for PSTN calls.

Diagnostic:
GET /v1/numbers
Find the number and check its "type" field.

Fix:
Use a number with type: "normal" and status: "active".

Cause 3: Source Number Not Owned by Customer

Problem:
The E.164 number is not in the customer's account or
has been deleted.

Diagnostic:
GET /v1/numbers
Verify the source number appears with status: "active".

Fix:
Purchase the number via POST /v1/numbers or use one
you already own.

Cause 4: Default Number Fallback

If the source fails validation, VoIPBIN checks the customer's
OutboundConfig for ``default_outgoing_source_number_id``.

If set: The call uses that number as caller ID (after re-validation
        against ``GET /v1/numbers`` filters: customer-owned, normal,
        active, not soft-deleted).
If unset (uuid.Nil) or the validated number is no longer valid:
        The call is rejected with no fallback.

To configure the default:
PUT https://api.voipbin.net/v1.0/outbound_config
{
  "default_outgoing_source_number_id": "<number-uuid>"
}

The number-uuid must be from GET /v1/numbers (an active
normal number you own). The default is re-validated at
call time, so a number that was valid when configured but
later released or deactivated will fail.

Note

AI Implementation Hint

When a user reports unexpected caller ID behavior, check three things: (1) the source number format (must be E.164 with +), (2) the number type via GET https://api.voipbin.net/v1.0/numbers (must be normal, not virtual), and (3) whether the customer’s OutboundConfig has default_outgoing_source_number_id set, via GET https://api.voipbin.net/v1.0/outbound_config (which returns the customer’s OutboundConfig). Non-PSTN calls (SIP, extension) skip source validation entirely and always use the provided source.

Call Rings But No Answer

Symptom: Call reaches ringing status, then hangs up. The hangup_reason is noanswer or dialout.

Understanding the difference:

"noanswer":
+------------------------------------------+
| The destination phone rang until the     |
| destination's voicemail or timeout       |
| kicked in.                               |
|                                          |
| Duration: Typically 30-60 seconds        |
| Cause: Nobody picked up                  |
+------------------------------------------+

"dialout":
+------------------------------------------+
| VoIPBIN's dial timeout expired before    |
| the call was answered.                   |
|                                          |
| Duration: Your configured timeout        |
| Cause: Your timeout is shorter than      |
|        typical ring time                 |
+------------------------------------------+

Fix for “noanswer”:

This is expected behavior when nobody answers.
- Consider using AMD to detect voicemail and leave a message
- Implement retry logic in your application
- Use groupcall with multiple destinations for fallback

Fix for “dialout”:

Increase dial_timeout in your call request:

POST /v1/calls
{
  "dial_timeout": 45000,
  "destinations": [...]
}

Default timeout is 30000 ms (30 seconds).
Recommended: 45000-60000 ms for PSTN calls.

Call Answers But No Audio

Symptom: Call reaches progressing status. One or both parties cannot hear each other. Call may disconnect after silence.

Diagnostic API call:

GET /v1/calls/{call-id}

Check these fields:
- status: should be "progressing"
- mute_direction: should be "" (empty = unmuted)

Cause 1: NAT/Firewall Issues (WebRTC)

Symptoms:
- WebRTC call connects (signaling OK)
- No audio in either direction

Fix:
- Ensure TURN server is configured
- Check client firewall allows UDP
- Verify ICE gathering completes
- Test with a different network

Cause 2: Codec Mismatch

Symptoms:
- SIP call connects
- RTP flows but audio is garbled or silent

Fix:
VoIPBIN auto-transcodes between codecs, but check
endpoint codec configuration if using SIP trunking.

Cause 3: Hold State Stuck

Symptoms:
- Call was working, then went silent
- One party can hear, other cannot

Diagnostic:
GET /v1/calls/{call-id}
{
  "mute_direction": "both"
}

Fix (unhold the call):
DELETE /v1/calls/{call-id}/hold

Fix (unmute the call):
DELETE /v1/calls/{call-id}/mute

Note

AI Implementation Hint

For WebRTC no-audio issues, the problem is almost always network-related (firewall, NAT, TURN). Check the browser’s developer console for ICE connection state errors. For SIP calls with one-way audio, the issue is typically NAT – the RTP packets are being sent to the wrong IP address. VoIPBIN’s RTPEngine handles most NAT traversal automatically.

Flow Actions Not Executing

Symptom: Call answers but expected TTS/media does not play. Actions seem to be skipped.

Diagnostic API call:

GET /v1/activeflows/{activeflow-id}

Look for error in current_action:
{
  "current_action": {
    "type": "talk",
    "error": "TTS service unavailable"
  }
}

Cause 1: early_execution Timing

Problem:
Actions execute before call answers.

With early_execution: true, actions start on INVITE
(before 200 OK). The call may not be ready for audio.

Fix:
Set early_execution: false (default).
Actions start after the call is answered (200 OK).

Cause 2: Action Errors

Problem:
An action fails and flow stops.

Diagnostic:
GET /v1/activeflows/{activeflow-id}

Fix:
Check the error message in current_action.
Verify action configuration (correct fields, valid IDs).

Cause 3: Missing Action IDs for Branching

Problem:
Branch targets an action ID that does not exist.

Example:
{
  "type": "branch",
  "option": {
    "target_ids": {
      "1": "nonexistent-id"
    }
  }
}

Fix:
Verify all target_ids match an action "id" in the same flow.
Use GET /v1/flows/{flow-id} to inspect the flow definition.

Note

AI Implementation Hint

If flow actions are not executing at all, verify that the call has a flow_id set (not 00000000-0000-0000-0000-000000000000). For outbound calls, you must either provide actions inline in POST /v1/calls or reference an existing flow via flow_id. For inbound calls, the flow is determined by the phone number configuration – check GET /v1/numbers/{number-id} for the flow_id assignment.

Webhooks Not Received

Symptom: No webhooks arrive at your endpoint, or only some webhooks arrive.

Diagnostic steps:

1. Verify webhook configuration on your customer profile:
GET /v1/customer

Check the webhook_method and webhook_uri fields:
{
  "webhook_method": "post",
  "webhook_uri": "https://your-server.com/webhook"
}

If webhook_uri is empty, webhooks are not configured.
Update via PUT /v1/customer with webhook_method and webhook_uri.

Cause 1: Endpoint not accessible

Symptoms:
- Delivery status is "failed"
- Error indicates connection refused or timeout

Fix:
- Whitelist VoIPBIN IP ranges in your firewall
- Use valid SSL certificate (self-signed certs are rejected)
- Ensure your endpoint returns HTTP 200 OK

Cause 2: Endpoint too slow

Symptoms:
- Webhook times out (> 5 seconds)
- VoIPBIN retries, causing duplicate deliveries

Fix:
- Return HTTP 200 immediately
- Process the webhook payload asynchronously
- Use a message queue (e.g., SQS, RabbitMQ) for processing

Cause 3: Webhook not configured on customer profile

Symptoms:
- No webhooks received at all

Diagnostic:
GET /v1/customer
Check that webhook_method is "post" and webhook_uri
is set to your endpoint URL.

Fix:
PUT /v1/customer
{
  "webhook_method": "post",
  "webhook_uri": "https://your-server.com/webhook"
}

Note

AI Implementation Hint

Webhook delivery is retried up to 3 times with exponential backoff. If all retries fail, the event is dropped. Always return HTTP 200 immediately and process asynchronously. Webhook configuration is managed via the customer profile: use GET /v1/customer to check webhook_method and webhook_uri, and PUT /v1/customer to update them. VoIPBIN sends all event types to your configured endpoint – there is no per-event subscription.

Recording Issues

Symptom: Recording not found, recording is empty or truncated, or recording URL does not work.

Diagnostic API call:

GET /v1/calls/{call-id}
Check the recording_ids array:
{
  "recording_ids": []
}

Cause 1: Recording Not Created

Symptoms:
- recording_ids array is empty

Possible reasons:
- record_start action not in flow
- Call hung up before recording started
- Error in recording action

Fix:
Verify flow has record_start action.
Check GET /v1/activeflows/{activeflow-id} for errors.

Cause 2: Recording Empty (duration 0)

Symptoms:
- Recording exists but duration is 0

Possible reasons:
- Recording started after call ended
- Audio not flowing during recording (call on mute)

Fix:
Place record_start early in the flow action list.
Verify call had audio (not on mute/hold).

Cause 3: Recording URL Returns 403

Symptoms:
- GET /v1/recordings/{id} returns a URL
- Downloading the URL fails with HTTP 403

Cause:
Signed URLs expire after 1 hour.

Fix:
Fetch a fresh URL from the API:
GET /v1/recordings/{recording-id}
Download immediately after getting the URL.

Note

AI Implementation Hint

Recording upload to cloud storage is asynchronous. After a call ends, the recording may take a few seconds to become available. If GET /v1/recordings/{recording-id} returns a recording without a url, the upload is still in progress. Poll the endpoint until url is populated. Cloud storage retention is 90 days by default – download recordings before they expire.

Transfer Problems

Symptom: Transfer fails, caller dropped during transfer, or consult call does not connect.

Diagnostic steps:

Use the transfer_id from the POST /transfers response
to look up the transfer object and inspect its state.

List transfers:
GET /v1/transfers

Cause 1: Blind Transfer Fails

Symptoms:
- Caller disconnected during transfer

Possible reasons:
- Transfer destination busy or unavailable
- No failover configured

Fix:
Use attended transfer for important calls.
Configure fallback action on failure.

Cause 2: Attended Transfer - Consult Fails

Symptoms:
- Agent A cannot reach Agent B

Diagnostic:
Check the transfer via GET /v1/transfers to find
the transfer and its associated call IDs.

Fix:
Verify the transferee address is correct and reachable.
Create a new transfer with a different destination.

Cause 3: Caller Hears Dead Air During Transfer

Symptoms:
- Hold music not playing during transfer

Possible reasons:
- MOH not configured
- Mute applied instead of hold

Fix:
Put the caller on hold before initiating the transfer:
POST /v1/calls/{call-id}/hold
POST /v1/calls/{call-id}/moh

Note

AI Implementation Hint

Transfers are initiated via POST /v1/transfers with transferer_call_id (UUID, obtained from GET /v1/calls) and transferee_addresses in the request body. The transfer_type field specifies attended or blind. The response includes a transfer_id (UUID) and associated call/groupcall IDs. If a blind transfer fails, the caller may be disconnected with no way to recover. For critical calls, always prefer attended transfer.

Queue Problems

Symptom: Calls not distributed to agents, long wait times, or agents not receiving calls.

Diagnostic API calls:

Check queue status:
GET /v1/queues/{queue-id}
{
  "wait_queuecall_ids": ["uuid-1", "uuid-2"],
  "service_queuecall_ids": []
}

Check agent status:
GET /v1/agents
Verify agents have status: "available"

Cause 1: No Available Agents

Symptoms:
- service_queuecall_ids is empty
- wait_queuecall_ids is growing

Possible reasons:
- All agents in "busy" or "offline" status
- Agents not logged into queue
- Agent status not updated after previous call

Fix:
Verify agent status via GET /v1/agents.
Ensure agents set their status to "available" after calls.

Cause 2: Calls Timing Out in Queue

Symptoms:
- Calls hang up after short wait

Diagnostic:
GET /v1/queues/{queue-id}
{
  "wait_timeout": 30000,
  "service_timeout": 60000
}

Fix:
Increase wait_timeout to give agents more time to answer:
PUT /v1/queues/{queue-id}
{
  "wait_timeout": 300000,
  "wait_flow_id": "voicemail-flow-uuid"
}

Note

AI Implementation Hint

The queue-id is a UUID obtained from GET /v1/queues. The wait_flow_id must reference a valid flow (obtained from GET /v1/flows) that handles the fallback (e.g., play a message and take a voicemail). Agent status is managed via PUT /v1/agents/{agent-id} with the status field. Common agent statuses are available, busy, away, and offline.

Error Reference

Hangup Reason Quick Reference:

+----------------+----------------------------------+------------------------+
| Reason         | Meaning                          | Action                 |
+----------------+----------------------------------+------------------------+
| normal         | Call completed successfully      | No action needed       |
| failed         | Network/routing failure          | Check number, routes   |
| busy           | Destination busy                 | Retry later            |
| noanswer       | No answer before timeout         | Leave voicemail        |
| cancel         | Caller cancelled                 | No action needed       |
| dialout        | VoIPBIN timeout                  | Increase dial_timeout  |
| timeout        | Max call duration exceeded       | Check timeout settings |
| amd            | Answering machine detected       | Expected behavior      |
+----------------+----------------------------------+------------------------+

Note

AI Implementation Hint

The hangup_reason field is the most important diagnostic field. failed means the call never reached the phone network (check number format, provisioning, balance). noanswer and dialout both mean nobody picked up, but dialout is your timeout while noanswer is the destination’s timeout. cancel means the originator hung up before the call was answered. amd means voicemail was detected and your AMD settings triggered a hangup.

HTTP Error Codes:

+------+----------------------------------+-------------------------------+
| Code | Meaning                          | Fix                           |
+------+----------------------------------+-------------------------------+
| 400  | Invalid request format           | Check request body JSON       |
|      |                                  | and required fields           |
+------+----------------------------------+-------------------------------+
| 401  | Authentication failed            | Check JWT token or access key |
|      |                                  | is valid and not expired      |
+------+----------------------------------+-------------------------------+
| 403  | Permission denied                | Check account permissions     |
|      |                                  | and resource ownership        |
+------+----------------------------------+-------------------------------+
| 404  | Resource not found               | Verify the UUID exists via    |
|      |                                  | the corresponding GET endpoint|
+------+----------------------------------+-------------------------------+
| 409  | Conflict (e.g., call ended)      | Resource state changed;       |
|      |                                  | re-fetch and retry            |
+------+----------------------------------+-------------------------------+
| 429  | Rate limit exceeded              | Slow down requests; implement |
|      |                                  | exponential backoff           |
+------+----------------------------------+-------------------------------+
| 500  | Server error                     | Contact support with the      |
|      |                                  | request ID from the response  |
+------+----------------------------------+-------------------------------+

Note

AI Implementation Hint

For HTTP 400 errors, the response body contains a detailed error message describing which field is invalid. For HTTP 404, always verify the resource ID by calling the corresponding list endpoint first (e.g., GET /v1/calls to verify a call-id exists before operating on it). For HTTP 429, implement exponential backoff starting at 1 second. For HTTP 500, include the x-request-id response header when contacting support.

Getting Help

If issues persist after troubleshooting, see Support for contact information and additional resources.