calls

Register the webhook for mid-call questions

Changed on

Register the HTTPS endpoint we POST to when the agent needs an answer from you during a call (a hostess asking for a callback number, or an IVR wanting a choice). If you subscribe with events, it also receives call_completed when a call finishes. Without one, those questions arrive on GET /calls/{call_id}/events and in pending_questions on GET /calls/{call_id}. While the subscription includes ask_user (the default), the same question goes to both channels carrying the same request_id; answer either, and deduplicate on that id. Reply 200 with an answer field to answer inline, or 202 and then POST /calls/{call_id}/answer when you have it. One 60-second budget covers the POST and the wait after it, and the callee is on hold for all of it.

put/users/me/webhook

Request

  • Base URL
    https://api.voygr.tech
  • URL
    https://api.voygr.tech/users/me/webhook
  • Auth
    API key in header X-API-Key

Request body

eventsstring[] nullable

Which webhooks this endpoint receives. Omit to leave the current subscription unchanged; [] receives nothing. 'ask_user' is the mid-call question: without it the webhook gets no questions, which then arrive on GET /calls/{call_id}/events and in pending_questions on GET /calls/{call_id}. 'call_completed' is one event when a call reaches its outcome, signed like ask_user. Its JSON body includes event ('call_completed'), call_id, outcome_type, result, ended_by, line_kind, result_reason, billable, charge_cents, charge_reason, summary, target_phone, started_at, ended_at and at; it carries no transcript or recording (read GET /calls/{call_id}). A failed delivery is retried with the same Webhook-Id, so deduplicate on it. A key that has never set this receives 'ask_user' only: call_completed is opt-in. An unknown value is refused with 422 unknown_webhook_event.

regenerate_secretboolean

Issue a new HMAC secret, invalidating the previous one. Defaults to true: keeping an old secret alive across a rotation would let anyone who captured it keep signing. Pass false to change only the URL. A key with no secret yet is issued one either way, otherwise the webhook would be unusable.

urlstring uri required

HTTPS endpoint. Plaintext HTTP is refused, because the payload carries the booking context and the HMAC header. The destination must be publicly routable: no credentials in the URL, no localhost, and nothing the host resolves to may be a private, link-local or otherwise reserved address. Delivery re-checks this and connects to the validated IP, so a host that passes here and later rebinds inward is refused at send time.

Example request

{
  "events": [
    "ask_user",
    "call_completed"
  ],
  "regenerate_secret": true,
  "url": "https://hooks.example.com/callwright"
}

Response

Registered. The secret is present only when this request issued one, and is shown once.

eventsstring[]

The subscription now in force, echoed back so you can check it.

secretstring nullable

The HMAC signing key, present only when this request issued a new one. null means the existing secret was kept, not that there is none. To verify a delivery: the POST carries Webhook-Id, Webhook-Timestamp and Webhook-Signature (Standard Webhooks v1). Recompute HMAC-SHA256 over the Webhook-Id, a dot, the Webhook-Timestamp, a dot, then the raw body bytes. Base64 the digest and compare it against the part after the 'v1,' prefix. The HMAC key is this secret string exactly as returned, UTF-8 encoded, with no whsec_ prefix. Do not base64-decode it first. That differs from the Standard Webhooks whsec_ convention, so a stock Standard Webhooks verifier needs the raw key passed to it, not this string. Sign the bytes you received, never a re-serialization of them: whitespace and key order change an encoding without changing what it means.

urlstring required

The canonicalized URL now registered. May differ from what you sent: the host is lowercased.

Example response

{
  "events": [
    "ask_user",
    "call_completed"
  ],
  "secret": "q3Jv8kX0bF5yW2mN7tL1cR9eHs4dZa6pU0iOgVnYxEw",
  "url": "https://hooks.example.com/callwright"
}

Changes

    • breaking

      the request property's minLength was increased from 0 to 1

    • breaking

      response property secret list-of-types was widened by adding types null to media type application/json of response 200

    • warning

      the request property's maxLength was set to 2000

    • info

      added the new optional request property

    • info

      added the optional property to the response with the status