Voicetta
    Voicetta.

    Voicetta Developers

    Quickstart

    See a real Voicetta call payload in under ten minutes, then write the handler. Includes the two rules that decide whether your integration behaves.

    Quickstart

    The fastest way to understand this API is to look at one real payload from your own workspace before you write any code.

    Step 1: See a real payload, without writing anything

    Do not start by building an endpoint. Start by pointing a throwaway URL at us and reading what arrives.

    1. Open a request bin — webhook.site, RequestBin, or an ngrok tunnel to your laptop. Copy the URL it gives you.
    2. In the Voicetta dashboard, go to Settings → Developers and create a webhook endpoint with that URL.
    3. Tick the blocks of data you want. The defaults are a good starting point.
    4. Press Send test event.

    We post your most recent real call to that URL and show you the status code it returned. The request bin shows you the exact headers and body.

    Two things to notice while you have it open:

    • The payload is one JSON object per call, not a stream of events you have to stitch together.
    • Null fields are absent, not null. That is the rule that catches most people later, so it is worth seeing it now.

    Send test event does not touch the delivery log or the retry schedule, so you can press it as often as you like while you are finding your footing.

    Step 2: Read one call over the API

    Now the other direction. Create an API key in the same settings page — tick the field groups it may read (same checklist as the webhook), then copy the key immediately. It is shown once.

    bash
    curl -H "Authorization: Bearer vk_live_your_key_here" \ "https://api.voicetta.com/v1/calls?limit=1"

    You get back a page of calls:

    json
    { "calls": [ { "call_id": "9f8b1c4e-6d2a-4b7f-8e21-3c5a7d9e0f11", "workspace_id": "2a1f8e7d-4c3b-4a29-9f18-6d5e4c3b2a19", "call_type": "inbound", "direction": "inbound", "status": "ended", "duration_seconds": 180, "analysis": { "summary": "Caller booked a double room for Friday." } } ], "has_more": true, "next_cursor": "MjAyNi0wOC0yMFQxMDowMDowMCswMDowMHw5ZjhiMWM0ZQ" }

    Narrow it to the blocks you actually want — but only within what the key was granted:

    bash
    curl -H "Authorization: Bearer vk_live_your_key_here" \ "https://api.voicetta.com/v1/calls?limit=1&fields=transcript"

    Requesting a block the key does not have returns 403. Omit fields to receive everything the key may read.

    If you got a 401, the key is revoked or the Bearer prefix is missing. Those are the only two causes.

    Step 3: Write the handler

    Now replace the request bin with your own endpoint. The smallest correct handler in Express:

    js
    app.post('/voicetta/calls', express.json(), (req, res) => { // Acknowledge first. Everything else happens after this line. res.sendStatus(200); const deliveryId = req.get('X-Voicetta-Delivery-Id'); if (alreadyProcessed(deliveryId)) { return; } enqueue(deliveryId, req.body.call); });

    That is the whole shape. Add signature verification next — see the webhook reference, which needs the raw body rather than parsed JSON.

    The two rules that decide whether this works

    Everything else in these docs is detail. These two are not.

    Acknowledge before you process

    Reply 200 as soon as the request arrives, then do your work. Write the payload to a queue or a table and return; do not insert into six tables, call three APIs, and then reply.

    If we do not get a response in time we assume the delivery failed and retry it. So slow processing does not just make things slow — it manufactures duplicate deliveries, and eventually marks deliveries as failed for calls your server actually received every single time.

    Assume you will receive the same call twice

    This is a property of every at-least-once delivery system, not a bug to be reported. If your 200 is lost on the way back to us, we retry a delivery you already handled perfectly.

    So make the handler idempotent. Dedupe on X-Voicetta-Delivery-Id, which is unique per attempt, or on call_id if you would rather key on the call itself and treat a repeat as an update.

    A handler that follows both rules is boring and reliable. One that follows neither will look fine in testing and produce duplicates in production.

    Step 4: Go live

    1. Confirm your endpoint is reachable from the public internet over HTTPS. We reject private and loopback addresses, so localhost and 10.x URLs will never work — use a tunnel while developing.
    2. Press Send test event again and confirm you see a 200.
    3. Ask us to enable delivery for your workspace.
    4. Watch the delivery log for the first few real calls.

    Test calls are never delivered to production endpoints, so your first real delivery will be a real call from a real person.