Answers to questions support commonly receives about the Public API. If your question isn't here, open a support ticket.
Setup
How much does it cost?
Standard Volume Reach per-minute rates apply to every Public API call. You're billed on:
- AI dial attempts — every call triggered (whether answered or not).
- AI connected minutes — only while the callee is on the line.
- Structured extraction — bundled into AI cost; typically well under $0.01 per call.
There is no separate Public API subscription fee or per-request fee. If you're on a PAYG plan, top up your wallet before heavy usage — calls return 402 insufficient_balance when the estimated cost exceeds wallet balance.
I got 403 public_api_disabled. How do I enable it?
The Public API is gated behind a per-tenant feature flag. For self-serve customers, it's enabled on request — open a support ticket with "Enable Public API" and we'll flip it within one business day. For customers on trial, the Public API is typically enabled automatically during sales onboarding.
What scopes do I actually need?
Create your API key with the scopes you plan to use. A typical production CRM integration needs all of:
calls:place— trigger + terminate callscalls:read— read call recordsread— list agents (optional but useful)webhooks— manage webhook endpoints + triggerswrite— save extraction schemas (optional)
Adding scopes later requires creating a new key — scopes can't be amended.
Calls
Why does POST /calls take 2–5 seconds to return?
The API synchronously verifies the agent, normalizes the phone number, reserves concurrent-call capacity, selects an outbound number, sets up the SIP trunk, and creates the LiveKit room before returning. This is intentional — you get a concrete call_id and early error feedback (invalid phone, missing variables, insufficient balance) rather than an async failure you'd have to handle via webhook.
If latency becomes a problem for your integration, we can move to a fully async "queued" return in a future version. Let us know.
Why is the returned status: "queued" — when does it actually dial?
Within milliseconds of the 201 response. "Queued" just means "the call is in our system, the SIP trunk is being dialed now". You'll see the status update via webhook events as the call progresses.
What happens if the lead doesn't answer?
The call record is marked with outcome NO_ANSWER, BUSY, VOICEMAIL, or similar. You still receive a call.completed webhook. duration_seconds is null for unanswered calls; transcript is empty or contains just the voicemail greeting (if voicemail drop was enabled).
My CRM is retrying POST /calls every 30 seconds due to network flakes. Am I calling the lead every time?
Only if you don't set idempotencyKey. Always include an idempotency key derived from your CRM's lead ID (e.g. idempotencyKey: "hubspot-lead-987-attempt-1"). Retries with the same key + same body return the original call_id without triggering a second dial. Retries with the same key + different body return 409 idempotency_conflict.
Can I cancel a call after it's been placed?
Call POST /calls/:id/end any time. If the call hasn't been answered yet, it cancels the ring. If it's in progress, the agent hangs up. The call.completed webhook fires with outcome CANCELED or similar.
Can I transfer the call to a human agent mid-conversation?
Not in v1. Deferred until there's sufficient customer demand.
Webhooks
I'm not receiving webhooks. What should I check?
In order:
- Run
GET /webhooks— confirm the endpoint exists andisActive: true. - Run
GET /automation-triggers— confirm a trigger exists forcall.completedpointing at your endpoint. - Open Settings → Automations in the Volume Reach app — it lists recent delivery attempts with response codes. If every recent delivery shows "SSRF blocked" or a specific error, that explains the gap.
- Verify your URL is reachable from the public internet (not
localhost, not behind VPN, not requiring client certificates). - Verify your endpoint returns
2xxwithin 10 seconds. Slow handlers or 5xx responses trigger retry.
How do I verify the webhook signature?
See webhooks.md#verifying-signatures. The critical thing is to verify against the raw request bytes, not a re-serialized parsed JSON body.
Can the same webhook fire twice?
Yes. Delivery is at-least-once. Retries after transient failures can produce duplicates. Design your handler to be idempotent — use the call_id as a dedup key. For example: if you see call.completed for a call_id you've already processed, return 200 and no-op.
My endpoint is slow and webhooks keep timing out. How do I fix this?
Move the slow work (CRM updates, Calendar bookings) into a background job. Your webhook handler should:
- Verify signature.
- Parse payload.
- Enqueue a job with the relevant data.
- Return 200.
This should complete in under 200ms. The enqueued job then handles CRM writes, external API calls, etc. on its own schedule.
How long are webhook delivery logs retained?
Delivery logs (visible in Settings → Automations) are retained for 30 days. After that, they're pruned. If you need longer retention, capture them on your end — the X-Webhook-Delivery-Id header is stable across retries so you can dedup + archive.
Can I subscribe to more granular events like call.ringing or call.answered?
Not in v1. The only subscribable Public API event is call.completed. More granular events exist in the internal event bus and will be exposed when there's clear customer demand.
Extraction
My extraction field is always null. Why?
One of:
- The agent has no
extractionSchemaconfigured. RunGET /agents/:idto verify. - The call has no transcript (e.g. no-answer call, or call disconnected before anyone spoke). Extraction only runs when there's a transcript to analyze.
- Extraction failed — check
extraction_erroron the same webhook payload.
The extracted values don't match what was actually said in the call
Two common causes:
- Vague field descriptions. The LLM extracts based on
descriptiontext in your schema — the more specific, the better. See extraction.md#authoring-the-schema. - Overly strict
required. Required fields must have a value even when the call didn't cover the topic — the LLM may invent a plausible answer. Usenullas a valid type for optional fields instead.
Test your schema against real transcripts in the OpenAI playground before relying on it.
Can I use a different extraction model (e.g. GPT-4o, Claude)?
v1 supports gpt-4.1-mini (default) and gpt-4o-mini. Both are fast + cheap + accurate enough for 2–3 minute qualification calls. Arbitrary models aren't supported to bound COGS.
How much does extraction cost?
About $0.0005–$0.002 per call, bundled into the call's aiCostUsd. Much less than the per-minute talk cost.
Compliance
Does Volume Reach scrub against the DNC registry?
Not in the Public API MVP. You are responsible for DNC scrubbing before calling our API. See compliance.md.
Do I have to set knownConsent: true?
You don't have to — calls go through either way. But you're legally responsible for having consent regardless, and setting the flag + consentRecordId creates an audit trail linking each call to the consent record that authorized it. Highly recommended.
Can I calls outside of business hours?
Volume Reach doesn't enforce time-window restrictions on the Public API. You should implement quiet hours in your own code (most CRMs know the recipient's timezone).
Account + keys
I lost my API key / signing secret. Can you recover it?
No. Both are shown only once at creation and stored hashed. To recover:
- API key: Settings → API Keys → create a new one. Revoke the old one.
- Webhook signing secret: Settings → Automations → click the endpoint → Rotate Secret. Deploy the new secret to your webhook server before the next delivery (there's no overlap window in v1).
How do I rotate an API key?
Create a new key with the scopes you need. Update your integration to use it. Revoke the old key (Settings → API Keys → Revoke).
My key was committed to a public git repo
- Immediately revoke it: Settings → API Keys → Revoke.
- Scan your billing history for unexpected calls.
- Rotate your webhook signing secrets too if the key had
webhooksscope — a stolen key + trigger list means the attacker knows where to attack next. - Create a new key, update your integration.
Debugging
How do I see what my call looked like?
GET /calls/:id returns the full call record including transcript, outcome, and a signed recording URL (15-min TTL). The Volume Reach app's Call Logs page shows the same data in a nicer UI.
A specific call is stuck in "queued". What happened?
Unusual — queued calls typically transition within a second or two. Possible causes:
- LiveKit cold start after a long idle period.
- Your SIP trunk is being provisioned for the first time (first-ever call per tenant).
- A platform issue.
Open a support ticket with the call_id and we'll check the pipeline logs.
How do I get help from Volume Reach Support?
Use the support chat bubble in the bottom-right of the Volume Reach app. Include in your message:
- Account email
- API key prefix (first 8 chars, e.g.
vr_live_ab; not the full key) - Specific
call_idorX-Webhook-Delivery-Idof the affected request - Approximate UTC timestamp
- What you expected vs what you saw
Support can't diagnose "webhooks stopped working" in the abstract, but with a delivery ID or call ID we can usually explain a specific failure within minutes.