Vocatech

Webhooks

Webhook events

Read from the API’s own reference file every hour.

Plain text

Each event is an HTTPS POST to your endpoint, in the same envelope with its own data. How to answer a delivery, check its signature and read its retries is on the endpoints page.

call.started

POSTAn extension started ringing or dialing.

An extension started ringing on an incoming call, or started dialing an outgoing one. end_time and duration are null.

We look for new call events every 5 seconds, so it usually arrives within seconds. Each event is one extension's view of the call: a call that rings several extensions can send one event per extension. Numbers are digits without the leading 1.

Known issue: group_number is one fixed number of your account, the same on every call event, not always the number that was dialed. A number_filters entry for your own number can miss these events.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways call.started.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.call_id requiredstringThe phone system's id for the call. It ties a call's events together. It is not always the same as call_id in GET /v1/calls.
data.direction requiredstringincoming, outgoing, or unknown when the phone system did not say. One of incoming, outgoing or unknown.
data.extension requiredstring or nullThe extension this event is about.
data.extension_name requiredstring or nullIts name, written First Last.
data.remote_name requiredstring or nullThe other party's name from caller ID.
data.remote_number requiredstring or nullThe other party's number, digits without the leading 1.
data.group_number requiredstring or nullOne number of your account, digits without the leading 1. Known issue: it is the same number on every call event, not always the number that was dialed.
data.start_time requiredstring (date-time) or nullUTC, ISO 8601 with milliseconds.
data.end_time requiredstring (date-time) or nullNull until the call ends.
data.duration requiredinteger or nullSeconds from answer to hang-up. Null until the call ends, and on a call nobody answered.
Example delivery
{
  "id": "evt_6703a1f25c9e8.21736450",
  "event_type": "call.started",
  "timestamp": "2026-09-24T14:03:14+00:00",
  "company_id": 1234567890,
  "data": {
    "call_id": "8a1f3c2e-5b7d-4e9a-9c1b-2d4e6f8a0b1c",
    "direction": "incoming",
    "extension": "104",
    "extension_name": "Maya Chen",
    "remote_name": "Jordan Reyes",
    "remote_number": "7185550142",
    "group_number": "7185550100",
    "start_time": "2026-09-24T14:03:12.000Z",
    "end_time": null,
    "duration": null
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

call.answered

POSTAn extension answered.

An extension answered the call. end_time and duration are null.

We look for new call events every 5 seconds, so it usually arrives within seconds. Each event is one extension's view of the call: a call that rings several extensions can send one event per extension. Numbers are digits without the leading 1.

Known issue: group_number is one fixed number of your account, the same on every call event, not always the number that was dialed. A number_filters entry for your own number can miss these events.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways call.answered.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.call_id requiredstringThe phone system's id for the call. It ties a call's events together. It is not always the same as call_id in GET /v1/calls.
data.direction requiredstringincoming, outgoing, or unknown when the phone system did not say. One of incoming, outgoing or unknown.
data.extension requiredstring or nullThe extension this event is about.
data.extension_name requiredstring or nullIts name, written First Last.
data.remote_name requiredstring or nullThe other party's name from caller ID.
data.remote_number requiredstring or nullThe other party's number, digits without the leading 1.
data.group_number requiredstring or nullOne number of your account, digits without the leading 1. Known issue: it is the same number on every call event, not always the number that was dialed.
data.start_time requiredstring (date-time) or nullUTC, ISO 8601 with milliseconds.
data.end_time requiredstring (date-time) or nullNull until the call ends.
data.duration requiredinteger or nullSeconds from answer to hang-up. Null until the call ends, and on a call nobody answered.
Example delivery
{
  "id": "evt_6703a1f3d7b21.58214907",
  "event_type": "call.answered",
  "timestamp": "2026-09-24T14:03:33+00:00",
  "company_id": 1234567890,
  "data": {
    "call_id": "8a1f3c2e-5b7d-4e9a-9c1b-2d4e6f8a0b1c",
    "direction": "incoming",
    "extension": "104",
    "extension_name": "Maya Chen",
    "remote_name": "Jordan Reyes",
    "remote_number": "7185550142",
    "group_number": "7185550100",
    "start_time": "2026-09-24T14:03:12.000Z",
    "end_time": null,
    "duration": null
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

call.ended

POSTA call ended.

The call ended for an extension. duration is seconds from answer to hang-up, or null when nobody answered.

We look for new call events every 5 seconds, so it usually arrives within seconds. Each event is one extension's view of the call: a call that rings several extensions can send one event per extension. Numbers are digits without the leading 1.

Known issue: group_number is one fixed number of your account, the same on every call event, not always the number that was dialed. A number_filters entry for your own number can miss these events.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways call.ended.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.call_id requiredstringThe phone system's id for the call. It ties a call's events together. It is not always the same as call_id in GET /v1/calls.
data.direction requiredstringincoming, outgoing, or unknown when the phone system did not say. One of incoming, outgoing or unknown.
data.extension requiredstring or nullThe extension this event is about.
data.extension_name requiredstring or nullIts name, written First Last.
data.remote_name requiredstring or nullThe other party's name from caller ID.
data.remote_number requiredstring or nullThe other party's number, digits without the leading 1.
data.group_number requiredstring or nullOne number of your account, digits without the leading 1. Known issue: it is the same number on every call event, not always the number that was dialed.
data.start_time requiredstring (date-time) or nullUTC, ISO 8601 with milliseconds.
data.end_time requiredstring (date-time) or nullNull until the call ends.
data.duration requiredinteger or nullSeconds from answer to hang-up. Null until the call ends, and on a call nobody answered.
Example delivery
{
  "id": "evt_6703a1f8e0c46.73920518",
  "event_type": "call.ended",
  "timestamp": "2026-09-24T14:09:43+00:00",
  "company_id": 1234567890,
  "data": {
    "call_id": "8a1f3c2e-5b7d-4e9a-9c1b-2d4e6f8a0b1c",
    "direction": "incoming",
    "extension": "104",
    "extension_name": "Maya Chen",
    "remote_name": "Jordan Reyes",
    "remote_number": "7185550142",
    "group_number": "7185550100",
    "start_time": "2026-09-24T14:03:12.000Z",
    "end_time": "2026-09-24T14:09:40.000Z",
    "duration": 369
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

call.transcription

POSTA recorded call has its transcript.

A recorded call leg has its transcript and AI summary. One event per recording: a call parked and picked up again is recorded in parts and sends one event per part.

It is sent once the finished transcript is ready, usually a few minutes after the call. We check every 2 minutes and wait up to 6 hours for the finished transcript. extension is the recorded leg's extension. The times and duration are the whole call's. direction reads as in GET /v1/calls.

recording_id, part, parts, recording_start_time and recording_duration say which recording the words are. Part N of a leg is GET /v1/media/rec_<n>?part=N and the same entry of recordings in GET /v1/calls. parts counts the parts saved when the event was sent. part is null for a recording of another call leg that is linked to the same leg of the report.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways call.transcription.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.call_id requiredstringThe phone system's id for the call.
data.direction requiredstringincoming or outgoing, as GET /v1/calls shows it.
data.extension requiredstring or nullThe extension on the recorded leg.
data.extension_name requiredstring or null
data.remote_name requiredstring or null
data.remote_number requiredstring or nullDigits without the leading 1.
data.group_number requiredstring or nullYour number on the call, digits without the leading 1.
data.start_time requiredstring (date-time) or nullThe call's start. UTC, ISO 8601 with milliseconds.
data.end_time requiredstring (date-time) or nullThe call's end. UTC, ISO 8601 with milliseconds.
data.duration requiredintegerThe call's length in seconds.
data.summary requiredstring or nullThe AI summary. Null when there is none.
data.transcription requiredstringThe transcript, with speaker labels.
data.recording_idintegerThe recording these words are, as in recordings in GET /v1/calls.
data.partinteger or nullThis recording's part of the leg, from 1. Null for a recording of another call leg linked to the same leg of the report.
data.partsinteger or nullHow many parts the leg's recording had when the event was sent. Nearly always 1.
data.recording_start_timestring (date-time) or nullWhen this recording started. UTC, ISO 8601 with milliseconds.
data.recording_durationinteger or nullThis recording's length in seconds.
Example delivery
{
  "id": "evt_6703a2b41f9d2.30481726",
  "event_type": "call.transcription",
  "timestamp": "2026-09-24T14:13:05+00:00",
  "company_id": 1234567890,
  "data": {
    "call_id": "8a1f3c2e-5b7d-4e9a-9c1b-2d4e6f8a0b1c",
    "direction": "incoming",
    "extension": "104",
    "extension_name": "Maya Chen",
    "remote_name": "Jordan Reyes",
    "remote_number": "7185550142",
    "group_number": "7185550100",
    "start_time": "2026-09-24T14:03:12.000Z",
    "end_time": "2026-09-24T14:09:40.000Z",
    "duration": 388,
    "summary": "Jordan Reyes asked to move the Thursday appointment to Friday at 10 AM. Maya Chen confirmed the new time and said a reminder text will follow.",
    "transcription": "Speaker 1: Good morning, thanks for calling. This is Maya.\nSpeaker 2: Hi Maya, this is Jordan Reyes. I need to move my Thursday appointment.\nSpeaker 1: No problem. Would Friday at 10 AM work?\nSpeaker 2: Friday at 10 is perfect. Thank you.",
    "recording_id": 10577702,
    "part": 2,
    "parts": 2,
    "recording_start_time": "2026-09-24T14:04:31.000Z",
    "recording_duration": 309
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

message.sent

POSTA text went out through the API or an automation.

A text left through the API or an automation: a send on a number in api or email mode, a picture message sent through the API, or a mass or group text. It is sent as soon as the carrier takes the message. message_id is the carrier's id, the same one the send returned. For a picture message sent through the API, attachments lists the URLs you sent.

Today a text sent from Webex does not fire message.sent. That includes POST /v1/messages on a Webex-mode number, replies your team types in Webex or sends by email, and WhatsApp replies. Those messages are in GET /v1/messages.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways message.sent.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.message_id requiredstring or nullFor a text, the carrier's message id: the same one a send in api or email mode returns and GET /v1/messages shows. For WhatsApp, the WhatsApp message id.
data.direction requiredstringOne of incoming or outgoing.
data.channel requiredstringOne of text or whatsapp.
data.from requiredstringE.164, like +17185550142.
data.to requiredstringE.164. On a group text, the recipients.
data.body requiredstringThe message text. Empty on most delivery receipts.
data.status requiredstringdelivered on received messages, sent on sent ones. On status updates: for a text delivered or failed; for WhatsApp its status, for example delivered, read or failed.
data.error requiredstring or nullWhy a message failed, from the carrier. Null otherwise.
data.sent_at requiredstring or nullWhen the message was sent or received, ISO 8601 as the source reported it. The offset varies.
data.attachments requiredarray, each object or string (uri)Files on the message. Received messages list objects. A picture message sent through the API lists the URLs you sent.
data.attachments[].url requiredstring (uri) or nullhttps://api.vocatech.com/v1/media/att_<n>: call it with your key for a signed link.
data.attachments[].content_type requiredstring or null
data.attachments[].filename requiredstring or null
data.attachments[].size requiredinteger or null
Example delivery
{
  "id": "evt_6703a3d19b6f2.17394056",
  "event_type": "message.sent",
  "timestamp": "2026-09-24T14:22:06+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_9b2e5a",
    "direction": "outgoing",
    "channel": "text",
    "from": "+17185550100",
    "to": "+17185550142",
    "body": "Friday at 10 AM works. See you then.",
    "status": "sent",
    "error": null,
    "sent_at": "2026-09-24T10:22:05-04:00",
    "attachments": []
  }
}
A picture message sent through the API
{
  "id": "evt_6703a3e2b0d58.47213960",
  "event_type": "message.sent",
  "timestamp": "2026-09-24T14:06:45+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_5d8f1b",
    "direction": "outgoing",
    "channel": "text",
    "from": "+17185550100",
    "to": "+17185550142",
    "body": "Here is the estimate we discussed.",
    "status": "sent",
    "error": null,
    "sent_at": "2026-09-24T10:06:44-04:00",
    "attachments": [
      "https://files.example.com/estimates/estimate-2291.pdf"
    ]
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

message.received

POSTA text or WhatsApp message arrived.

A text or WhatsApp message arrived on one of your numbers. It is sent as soon as the message arrives.

attachments lists each picture or file with its link to GET /v1/media. A file we could not store has url set to null.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways message.received.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.message_id requiredstring or nullFor a text, the carrier's message id: the same one a send in api or email mode returns and GET /v1/messages shows. For WhatsApp, the WhatsApp message id.
data.direction requiredstringOne of incoming or outgoing.
data.channel requiredstringOne of text or whatsapp.
data.from requiredstringE.164, like +17185550142.
data.to requiredstringE.164. On a group text, the recipients.
data.body requiredstringThe message text. Empty on most delivery receipts.
data.status requiredstringdelivered on received messages, sent on sent ones. On status updates: for a text delivered or failed; for WhatsApp its status, for example delivered, read or failed.
data.error requiredstring or nullWhy a message failed, from the carrier. Null otherwise.
data.sent_at requiredstring or nullWhen the message was sent or received, ISO 8601 as the source reported it. The offset varies.
data.attachments requiredarray, each object or string (uri)Files on the message. Received messages list objects. A picture message sent through the API lists the URLs you sent.
data.attachments[].url requiredstring (uri) or nullhttps://api.vocatech.com/v1/media/att_<n>: call it with your key for a signed link.
data.attachments[].content_type requiredstring or null
data.attachments[].filename requiredstring or null
data.attachments[].size requiredinteger or null
Example delivery
{
  "id": "evt_6703a3c07a5e1.64820193",
  "event_type": "message.received",
  "timestamp": "2026-09-24T14:20:32+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_7f3a9c",
    "direction": "incoming",
    "channel": "text",
    "from": "+17185550142",
    "to": "+17185550100",
    "body": "Can we move my appointment to Friday?",
    "status": "delivered",
    "error": null,
    "sent_at": "2026-09-24T14:20:31.512Z",
    "attachments": [
      {
        "url": "https://api.vocatech.com/v1/media/att_90211",
        "content_type": "image/jpeg",
        "filename": "photo-0924.jpg",
        "size": 184233
      }
    ]
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

message.status_updated

POSTThe carrier reported on a text.

The carrier reported what happened to a text you sent, or WhatsApp reported a status change. It is sent as soon as the report arrives.

For a text, status is delivered, or failed with the carrier's reason in error. A text whose receipt never came back sends no event. For WhatsApp, status is the WhatsApp status, for example delivered, read or failed. body is empty except on a failed text. Match message_id to the send or to GET /v1/messages.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways message.status_updated.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.message_id requiredstring or nullFor a text, the carrier's message id: the same one a send in api or email mode returns and GET /v1/messages shows. For WhatsApp, the WhatsApp message id.
data.direction requiredstringOne of incoming or outgoing.
data.channel requiredstringOne of text or whatsapp.
data.from requiredstringE.164, like +17185550142.
data.to requiredstringE.164. On a group text, the recipients.
data.body requiredstringThe message text. Empty on most delivery receipts.
data.status requiredstringdelivered on received messages, sent on sent ones. On status updates: for a text delivered or failed; for WhatsApp its status, for example delivered, read or failed.
data.error requiredstring or nullWhy a message failed, from the carrier. Null otherwise.
data.sent_at requiredstring or nullWhen the message was sent or received, ISO 8601 as the source reported it. The offset varies.
data.attachments requiredarray, each object or string (uri)Files on the message. Received messages list objects. A picture message sent through the API lists the URLs you sent.
data.attachments[].url requiredstring (uri) or nullhttps://api.vocatech.com/v1/media/att_<n>: call it with your key for a signed link.
data.attachments[].content_type requiredstring or null
data.attachments[].filename requiredstring or null
data.attachments[].size requiredinteger or null
Example delivery
{
  "id": "evt_6703a3d4c1a07.92057341",
  "event_type": "message.status_updated",
  "timestamp": "2026-09-24T14:22:09+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_9b2e5a",
    "direction": "outgoing",
    "channel": "text",
    "from": "+17185550100",
    "to": "+17185550142",
    "body": "",
    "status": "delivered",
    "error": null,
    "sent_at": "2026-09-24T14:22:07.880Z",
    "attachments": []
  }
}
A text that failed
{
  "id": "evt_6703a3d6e8b14.30958216",
  "event_type": "message.status_updated",
  "timestamp": "2026-09-24T14:25:40+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_1e7b4d",
    "direction": "outgoing",
    "channel": "text",
    "from": "+17185550100",
    "to": "+17185550143",
    "body": "Friday at 10 AM works. See you then.",
    "status": "failed",
    "error": "Carrier rejected the message",
    "sent_at": "2026-09-24T14:25:38.214Z",
    "attachments": []
  }
}
WhatsApp read
{
  "id": "evt_6703a3d9a2c75.11846230",
  "event_type": "message.status_updated",
  "timestamp": "2026-09-24T14:31:12+00:00",
  "company_id": 1234567890,
  "data": {
    "message_id": "msg_6f0a2c",
    "direction": "outgoing",
    "channel": "whatsapp",
    "from": "+17185550100",
    "to": "+17185550142",
    "body": "",
    "status": "read",
    "error": null,
    "sent_at": "2026-09-24 14:31:10",
    "attachments": []
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

fax.sent

POSTAn outgoing fax is in progress.

An outgoing fax was handed to the fax carrier and is in progress.

We look for new faxes on a schedule. Each fax is read once, when it first appears, and the event is chosen by its status at that moment. A later change sends no further event: a fax that finishes after we first saw it sends no fax.delivered or fax.failed. Read the final status with GET /v1/faxes.

Known issue: sent_at is Eastern time written with a Z, so it reads 4 or 5 hours early.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways fax.sent.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.fax_id requiredstringUse it with GET /v1/media/{id} once the document is ready. Matches ^fax_[0-9]+$.
data.direction requiredstringOne of incoming or outgoing.
data.from requiredstringE.164.
data.to requiredstringE.164.
data.pages requiredinteger or null
data.subject requiredstring or null
data.status requiredstringOne of in_progress, completed, failed, restricted or unknown.
data.faxage_job_id requiredstring or nullThe fax carrier's job id.
data.sent_at requiredstring (date-time) or nullWhen the fax was logged. Known issue: Eastern time written with a Z, so it reads 4 or 5 hours early.
Example delivery
{
  "id": "evt_6703a41e2d8b3.48102967",
  "event_type": "fax.sent",
  "timestamp": "2026-09-24T14:06:02+00:00",
  "company_id": 1234567890,
  "data": {
    "fax_id": "fax_77120",
    "direction": "outgoing",
    "from": "+17185550100",
    "to": "+17185550142",
    "pages": null,
    "subject": "Intake form",
    "status": "in_progress",
    "faxage_job_id": "93125501",
    "sent_at": "2026-09-24T10:05:09.000Z"
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

fax.received

POSTAn incoming fax is arriving.

An incoming fax was logged while it was still arriving. An incoming fax that was logged already complete comes as fax.delivered instead.

We look for new faxes on a schedule. Each fax is read once, when it first appears, and the event is chosen by its status at that moment. A later change sends no further event: a fax that finishes after we first saw it sends no fax.delivered or fax.failed. Read the final status with GET /v1/faxes.

Known issue: sent_at is Eastern time written with a Z, so it reads 4 or 5 hours early.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways fax.received.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.fax_id requiredstringUse it with GET /v1/media/{id} once the document is ready. Matches ^fax_[0-9]+$.
data.direction requiredstringOne of incoming or outgoing.
data.from requiredstringE.164.
data.to requiredstringE.164.
data.pages requiredinteger or null
data.subject requiredstring or null
data.status requiredstringOne of in_progress, completed, failed, restricted or unknown.
data.faxage_job_id requiredstring or nullThe fax carrier's job id.
data.sent_at requiredstring (date-time) or nullWhen the fax was logged. Known issue: Eastern time written with a Z, so it reads 4 or 5 hours early.
Example delivery
{
  "id": "evt_6703a5a07e4c9.26039174",
  "event_type": "fax.received",
  "timestamp": "2026-09-24T15:39:31+00:00",
  "company_id": 1234567890,
  "data": {
    "fax_id": "fax_77131",
    "direction": "incoming",
    "from": "+12125550187",
    "to": "+17185550100",
    "pages": null,
    "subject": null,
    "status": "in_progress",
    "faxage_job_id": "93125870",
    "sent_at": "2026-09-24T11:39:02.000Z"
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

fax.delivered

POSTA fax completed.

A fax was logged as completed when we first saw it. Fetch the document with GET /v1/media/{fax_id}.

We look for new faxes on a schedule. Each fax is read once, when it first appears, and the event is chosen by its status at that moment. A later change sends no further event: a fax that finishes after we first saw it sends no fax.delivered or fax.failed. Read the final status with GET /v1/faxes.

Known issue: sent_at is Eastern time written with a Z, so it reads 4 or 5 hours early.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways fax.delivered.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.fax_id requiredstringUse it with GET /v1/media/{id} once the document is ready. Matches ^fax_[0-9]+$.
data.direction requiredstringOne of incoming or outgoing.
data.from requiredstringE.164.
data.to requiredstringE.164.
data.pages requiredinteger or null
data.subject requiredstring or null
data.status requiredstringOne of in_progress, completed, failed, restricted or unknown.
data.faxage_job_id requiredstring or nullThe fax carrier's job id.
data.sent_at requiredstring (date-time) or nullWhen the fax was logged. Known issue: Eastern time written with a Z, so it reads 4 or 5 hours early.
Example delivery
{
  "id": "evt_6703a5b3f1d06.85216403",
  "event_type": "fax.delivered",
  "timestamp": "2026-09-24T15:41:02+00:00",
  "company_id": 1234567890,
  "data": {
    "fax_id": "fax_77135",
    "direction": "incoming",
    "from": "+12125550187",
    "to": "+17185550100",
    "pages": 2,
    "subject": null,
    "status": "completed",
    "faxage_job_id": "93125877",
    "sent_at": "2026-09-24T11:40:00.000Z"
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.

fax.failed

POSTA fax failed.

A fax was logged as failed or restricted when we first saw it, for example an outgoing fax the carrier refused at once.

We look for new faxes on a schedule. Each fax is read once, when it first appears, and the event is chosen by its status at that moment. A later change sends no further event: a fax that finishes after we first saw it sends no fax.delivered or fax.failed. Read the final status with GET /v1/faxes.

Known issue: sent_at is Eastern time written with a Z, so it reads 4 or 5 hours early.

Headers

NameInTypeDescription
X-Vocatech-Signature requiredheaderstringt=<unix seconds>,v1=<hex HMAC-SHA256 of t=<t>.<raw body>, keyed with your secret_key>. Reject the delivery if t is more than 300 seconds from your clock or v1 does not match. For example t=1790259302,v1=4e1c9a7b2f5d8e3a6c0b9f2e5d8a1c4b7e0f3a6d9c2b5e8f1a4d7c0b3e6f9a2d.
X-Vocatech-Event requiredheaderstringThe event type, the same as event_type in the body.
User-Agent requiredheaderstringAlways Vocatech-Webhook/1.0. Always Vocatech-Webhook/1.0.

Payload

FieldTypeDescription
id requiredstringA unique id for this delivery's event. Retries repeat it. Use it to skip duplicates. For example evt_6703a1f25c9e8.21736450.
event_type requiredstringAlways fax.failed.
timestamp requiredstring (date-time)When we built the event. ISO 8601 with +00:00.
company_id requiredintegerYour company id.
data requiredobject
data.fax_id requiredstringUse it with GET /v1/media/{id} once the document is ready. Matches ^fax_[0-9]+$.
data.direction requiredstringOne of incoming or outgoing.
data.from requiredstringE.164.
data.to requiredstringE.164.
data.pages requiredinteger or null
data.subject requiredstring or null
data.status requiredstringOne of in_progress, completed, failed, restricted or unknown.
data.faxage_job_id requiredstring or nullThe fax carrier's job id.
data.sent_at requiredstring (date-time) or nullWhen the fax was logged. Known issue: Eastern time written with a Z, so it reads 4 or 5 hours early.
Example delivery
{
  "id": "evt_6703a60c4a2e8.60371925",
  "event_type": "fax.failed",
  "timestamp": "2026-09-24T16:02:03+00:00",
  "company_id": 1234567890,
  "data": {
    "fax_id": "fax_77140",
    "direction": "outgoing",
    "from": "+17185550100",
    "to": "+17185550142",
    "pages": null,
    "subject": "Intake form",
    "status": "failed",
    "faxage_job_id": null,
    "sent_at": "2026-09-24T12:01:40.000Z"
  }
}

Your answer

2XX
Received. Answer within 5 seconds, then do the work.
Other
Any other status, no answer within 5 seconds, or a redirect is a failed delivery. We retry it.