Momo sends this request to your configured webhook URL. It is an incoming callback, not an API endpoint to call.
Request body
application/json · required
The event payload.
eventstringrequired
Event name. The full list with a sample payload each is at `GET /api/v3/webhooks/events`; the dashboard picker and this enum both read the same catalogue.
- enum
["message.received","message.sent","message.delivered","message.read","message.failed","message.echoed","message.updated","order.received","order.status_changed","order.cancelled","order.paid","sync.completed","stock.low","product.blocked","product.drifted","campaign.completed","campaign.failed","group.created","group.create_failed","group.updated","group.deleted","group.suspended","group.suspension_cleared","group.participant_joined","group.participant_left","group.participant_removed","group.join_requested","group.join_request_revoked","group.invite_sent","template.status_changed","form.submitted","form.status_changed","webhook.paused","cart.submitted","cart.abandoned","flow.session.started","flow.session.ended","lead.created","lead.updated","lead.stage_changed","lead.label_added","lead.label_removed","lead.note_added","lead.assigned","lead.merged","lead.deleted","voice.otp.answered","voice.otp.completed","voice.otp.failed","voice.message.answered","voice.message.completed","voice.message.failed","call.completed","call.recording_ready","call.feedback_ready","call_campaign.started","call_campaign.target_completed","call_campaign.paused","call_campaign.resumed","call_campaign.completed","call_campaign.failed","webhook.test"]
timestampstringrequired
Dispatch time in ISO8601.
- format
date-time
message_idintegeroptional
Message events: local numeric message ID, usable in SMS/WhatsApp lookup.
directionstringoptional
Message direction.
- enum
["inbound","outbound"]
senderstring | nulloptional
Message sender identity.
recipientstringoptional
Message recipient identity.
statusstringoptional
Message delivery state.
bodystring | nulloptional
Message body.
media_urlstring | nulloptional
Attached media URL.
channel_typestring | nulloptional
Message channel type.
order_idintegeroptional
Order events: local order ID.
customer_wa_idstringoptional
order.received: customer WhatsApp identifier.
customer_namestring | nulloptional
order.received: customer name.
product_itemsarray<object>optional
order.received: incoming cart items.
Show child properties
product_retailer_idstringoptional
The SKU the customer added to the cart.
quantityintegeroptional
How many.
item_priceintegeroptional
Unit price in the minor unit of `currency`.
currencystringoptional
ISO 4217 currency code.
unit_price_minorinteger | nulloptional
Unit price in the minor unit. Prefer this over `item_price`, which is Meta's own field and is in MAJOR units.
line_total_minorinteger | nulloptional
Unit price times quantity, in the minor unit.
reservedinteger | nulloptional
How many units of this line are actually being held for the order.
stock_shortboolean | nulloptional
True when we could not hold the whole quantity. The order was still recorded.
unresolvedboolean | nulloptional
True when this product code is not in the catalogue. The code is kept verbatim so a person can work out what the customer meant.
total_amountintegeroptional
order.received: total in integer hundredths.
total_currencystringoptional
order.received: currency code.
customer_notestring | nulloptional
order.received: customer note.
conversation_idinteger | nulloptional
Order event: linked conversation ID.
created_atstringoptional
order.received: creation time.
- format
date-time
payment_idintegeroptional
order.paid: payment ID.
methodstringoptional
order.paid: payment method.
amount_minorintegeroptional
order.paid: paid amount in minor units.
currencystringoptional
order.paid: currency code.
payer_msisdnstring | nulloptional
order.paid: payer phone number.
paid_atstring | nulloptional
order.paid: settlement time.
- format
date-time
groupobjectoptional
Current local WhatsApp group summary, when the event concerns a group.
Show child properties
idintegerrequired
Platform id of the group; what every group endpoint takes.
meta_group_idstring | nulloptional
WhatsApp's own group id. Null while the group is still being created.
request_idstring | nulloptional
WhatsApp's create request id; how the confirmation webhook is matched.
phone_number_idstringoptional
The business number the group was created from.
waba_idstring | nulloptional
The WhatsApp Business Account the number belongs to.
subjectstringrequired
The group name, up to 128 characters.
- maxLength
128
descriptionstring | nulloptional
What the group is for; members see it before joining. Up to 2048 characters.
- maxLength
2048
join_approval_modestringoptional
auto_approve: anyone with the link joins. approval_required: the business approves each request.
- enum
["auto_approve","approval_required"]
invite_linkstring | nulloptional
The chat.whatsapp.com link people tap to join. Null until WhatsApp confirms the group.
statusstringrequired
creating (waiting for WhatsApp), active, suspended (by WhatsApp, for policy), deleted, or failed (WhatsApp refused to create it; see last_error).
- enum
["creating","active","suspended","deleted","failed"]
participant_countintegerrequired
Members besides the business.
max_participantsintegerrequired
8, the business counted in.
seats_leftintegeroptional
How many more people can join.
pending_join_requestsintegeroptional
People waiting for approval on an approval_required group.
conversation_idinteger | nulloptional
The inbox thread for the group.
invite_template_idinteger | nulloptional
The approved template used for invites from this group.
last_message_atstring | nulloptional
When the thread last had a message, either way.
- format
date-time
last_errorobject | array | nulloptional
WhatsApp's last refusal, when there was one.
last_synced_atstring | nulloptional
When the roster and settings were last read back from WhatsApp.
- format
date-time
created_atstring | nulloptional
When the platform created the record.
- format
date-time
updated_atstring | nulloptional
When it last changed.
- format
date-time
wa_idsarray<string>optional
Participant event: affected WhatsApp IDs.
reasonstring | nulloptional
Participant event reason when supplied. lead.stage_changed: the reason given for lost or unqualified.
appliedobjectoptional
group.updated: applied settings.
- additionalProperties
true
errorsarray | object | nulloptional
Provider/group error details.
- additionalProperties
true
sentinteger | arrayoptional
group.invite_sent: successfully sent invitations.
failedinteger | arrayoptional
group.invite_sent: failed invitations.
template_idintegeroptional
template.status_changed: local template id, for `GET /api/v3/whatsapp/templates/{template}`.
namestringoptional
template.status_changed: the template name.
languagestringoptional
template.status_changed: the template language.
whatsapp_business_account_idstringoptional
template.status_changed: the WhatsApp Business Account whose review moved.
whatsapp_template_idstring | nulloptional
template.status_changed: Meta's id on that account.
previous_statusstring | nulloptional
template.status_changed: the status before this change.
whatsapp_statusstringoptional
template.status_changed: the status now.
- enum
["pending","in_review","approved","rejected","disabled","paused"]
rejection_reasonstring | nulloptional
template.status_changed: Meta's reason when the new status is rejected.
event_idstringoptional
This event's id: `evt_` + a ULID. The same on every retry and replay and on every endpoint that receives the event — dedupe on this (also sent as `X-Event-Id`).
leadobjectoptional
lead.* events: the whole lead as it is now.
Show child properties
idstringoptional
Lead id (uuid).
- format
uuid
namestring | nulloptional
Name.
phonestring | nulloptional
Phone, E.164.
emailstring | nulloptional
Email.
companystring | nulloptional
Company.
locationstring | nulloptional
Area or city.
stagestringoptional
Stage.
- enum
["new","contacted","qualified","opportunity","won","lost","unqualified"]
closed_atstring | nulloptional
When it closed; null while open.
- format
date-time
archived_atstring | nulloptional
When it was archived.
- format
date-time
lost_reasonstring | nulloptional
Why it was lost or disqualified.
source_channelstringoptional
Where it first came from.
- enum
["call","whatsapp","sms","messenger","instagram","tiktok","email","comment","form","web","chat","manual","import","api"]
source_detailstring | nulloptional
A human line about the origin.
intereststring | nulloptional
What they want.
estimated_valuenumber | nulloptional
Deal size, main units.
currencystringoptional
ISO 4217 code.
scoreinteger | nulloptional
Score 0–100.
score_reasonstring | nulloptional
Why that score.
summarystring | nulloptional
What they need.
next_actionstring | nulloptional
Next thing to do.
next_action_atstring | nulloptional
When it is due.
- format
date-time
labelsarray<string>optional
Label names.
assigned_toobject | nulloptional
The team member who looks after the lead; null while it waits in the unassigned pool.
Show child properties
idintegeroptional
Team member id.
namestringoptional
Their name.
custom_fieldsobjectoptional
Custom field values by key.
- additionalProperties
true
created_byobjectoptional
Who added the lead.
Show child properties
kindstringoptional
user, ai, mcp, api, flow, form, import or system.
- enum
["user","ai","mcp","api","flow","form","import","system"]
idinteger | nulloptional
The person, AI agent or credential id behind that kind, when there is one.
created_atstring | nulloptional
When it was added.
- format
date-time
updated_atstring | nulloptional
When it last changed.
- format
date-time
urlstringoptional
The lead's page in the dashboard.
- format
uri
changesobjectoptional
lead.updated, lead.stage_changed, lead.assigned: `{field: {from, to}}`. A burst of updates within about five seconds arrives as one lead.updated with the changes folded together.
- additionalProperties
true
actorobjectoptional
lead.* events: who made the change.
Show child properties
kindstringoptional
user, ai, mcp, api, flow, form, import or system.
idinteger | nulloptional
The person, AI agent or credential id, when there is one.
labelstring | nulloptional
Their name at the time.
sourceobject | nulloptional
lead.* events: the call or conversation the change happened in, if any.
Show child properties
kindstringoptional
call, conversation, comment, form_answer, email or contact.
idstringoptional
That record's id, as a string.
channelstring | nulloptional
Its channel.
labelobjectoptional
lead.label_added / lead.label_removed: the label.
Show child properties
namestringoptional
Label name.
colorstringoptional
Hex colour.
noteobjectoptional
lead.note_added: the note.
Show child properties
bodystringoptional
The note text.
authorstring | nulloptional
Who wrote it.
merged_idstringoptional
lead.merged: the id of the lead that was merged into `lead` and no longer exists.
- format
uuid
testbooleanoptional
webhook.test and any sample sent with the Test button: true. Never set on a real event.
messagestringoptional
webhook.test: a sentence saying what this is.
callobjectoptional
call.*: the call (the same object GET /api/v3/calls/{id} returns). call.* events are sent only for calls a call campaign or POST /api/v3/calls placed.
Show child properties
idintegerrequired
The call id: GET /api/v3/calls/{id}.
room_namestringrequired
The phone system's handle for the call.
directionstringrequired
inbound or outbound.
statusstringrequired
Where the call is: ringing, in_progress, ended, missed, failed …
outcomestring | nullrequired
How it ended, once it has: answered, no_answer, busy, declined, busy_or_declined, unavailable, unreachable, provider_failure, cancelled, billing_rejected, unknown.
answeredbooleanrequired
Someone (or the AI / IVR) picked up.
fromstring | nullrequired
The calling number.
tostring | nullrequired
The number called.
modestring | nulloptional
message, ai or ivr for calls placed by the API or a campaign.
agent_config_idstring | nulloptional
The AI agent that talked, if any.
sourcestring | nulloptional
Who placed it: api, app, mcp, campaign, or the device / system for other calls.
started_atstring | nullrequired
When it started ringing (ISO 8601).
answered_atstring | nulloptional
When it was answered.
ended_atstring | nullrequired
When it ended.
duration_secondsintegerrequired
How long it lasted.
sip_status_codeinteger | nulloptional
The carrier's SIP status, when the phone system saw one (486 busy, 480 unavailable …).
keys_pressedarray<object>required
Every key pressed, in order, with what it meant.
Show child properties
digitstring | nullrequired
The digit (0-9, *, #). Null when the phone system redacted it (PIN entry in an IVR).
actionstring | nullrequired
What the key was set to do (confirm, tag, start_flow, opt_out …), or the phone system's word for it when nothing was set.
labelstring | nullrequired
The key's label, as set on the campaign or the API request.
atstring | nullrequired
When it was pressed (ISO 8601).
recording_availablebooleanrequired
A recording exists: GET /api/v3/calls/{id}/recordings.
transcript_availablebooleanrequired
A transcript exists: GET /api/v3/calls/{id}/transcript.
requestobject | nullrequired
What POST /api/v3/calls was asked for, when this call was placed that way; null otherwise.
Show child properties
external_refstring | nulloptional
Your own reference, as sent.
purposestring | nulloptional
Why we are calling, as sent (AI calls).
variablesobjectoptional
The person's details, as sent.
- additionalProperties
{"type":"string","description":"A detail value."}
estimated_costnumberoptional
What one answered call was estimated to cost.
campaignobject | nullrequired
The campaign person this call was for, when it was a campaign call; null otherwise.
Show child properties
idstringoptional
The campaign id.
namestring | nulloptional
The campaign name.
target_idintegeroptional
The person's row in the campaign.
external_idstring | nulloptional
Your own id for the person, as sent.
tryintegeroptional
Which try this was.
resultstring | nulloptional
The try's result: reached, pressed, no_answer, busy …
campaignobjectoptional
call_campaign.*: the campaign (the same object GET /api/v3/call-campaigns/{id} returns); on call_campaign.target_completed only its id, name, external_ref and is_rolling.
- additionalProperties
true
targetobjectoptional
call_campaign.target_completed: the person, echoing your external_id and variables.
Show child properties
idintegeroptional
The person's row id.
positionintegeroptional
Their place in the list (1-based): GET …/targets?position=N starts there.
tostringoptional
The number called (E.164).
namestring | nulloptional
Their name.
external_idstring | nulloptional
Your own id for them (an order, a loan, a Daftari record, a lead).
contact_idinteger | nulloptional
Their contact, when they came from a contact group.
resultstringoptional
waiting, calling, reached, pressed, no_answer, busy, switched_off, voicemail, declined, wrong_number, opted_out, our_problem, callback, not_reached or skipped.
result_labelstringoptional
The result in words: "Pressed 1", "No answer" …
skip_reasonstring | nulloptional
Why they were skipped, when result is skipped: whatsapp_permission_required (a WhatsApp campaign, and they have not allowed WhatsApp calls from the business; never retried), dispatch_failed, or callback_<status> for a call-back that was cancelled. Null otherwise.
finalbooleanoptional
Nothing more will happen for this person.
triesintegeroptional
Calls that counted as a try.
max_triesintegeroptional
Tries allowed.
next_try_atstring | nulloptional
When they will be tried again.
keys_pressedarray<string>optional
Digits pressed, in order.
answersobjectoptional
What they answered: confirmed, interested, an AI answer field, tags …
- additionalProperties
true
summarystring | nulloptional
The AI's one-line summary of them.
variablesobjectoptional
Their details, as sent ({jina}, {kiasi} …).
- additionalProperties
{"type":"string","description":"A detail value."}
last_call_idinteger | nulloptional
Their latest call: GET /api/v3/calls/{id}.
last_call_atstring | nulloptional
When they were last called.
costnumberoptional
What their calls cost.
created_atstring | nulloptional
When they were added.
recordingobjectoptional
call.recording_ready: the recording.
Show child properties
idinteger | nulloptional
The recording id.
duration_secondsinteger | nulloptional
Length.
statusstringoptional
complete …
list_urlstringoptional
GET it with your key for the audio link.
feedbackobjectoptional
call.feedback_ready: the AI's summary of the call.
Show child properties
summarystring | nulloptional
One-paragraph summary.
sentimentstring | nulloptional
positive, neutral or negative.
dispositionstring | nulloptional
How the call ended, in the AI's words.
key_topicsarray<string>optional
Topics raised.
action_itemsarray<string>optional
Things to do.
next_best_actionstring | nulloptional
What to do next.
answersobjectoptional
call.feedback_ready on a campaign call: the person's answers so far.
- additionalProperties
true
statestringoptional
call_campaign.completed: finished (everyone called) or stopped (ended early).
automaticbooleanoptional
call_campaign.paused / .resumed: the campaign did it by itself (wallet low, needs attention, wallet topped up).
top_upnumberoptional
call_campaign.paused with reason wallet_low: how much to top up to continue.
attention_reasonstringoptional
call_campaign.paused with reason needs_attention: caller_number_disabled, agent_deleted, ivr_unpublished, pbx_unreachable or message_invalid.
campaign_uidstringoptional
campaign.completed / campaign.failed: the SMS campaign.
recipientsintegeroptional
campaign.completed: people the SMS campaign went to.
channelstringoptional
campaign.completed / campaign.failed: sms or whatsapp.
Complete request schema
{
"type": "object",
"properties": {
"event": {
"type": "string",
"description": "Event name. The full list with a sample payload each is at `GET /api/v3/webhooks/events`; the dashboard picker and this enum both read the same catalogue.",
"enum": [
"message.received",
"message.sent",
"message.delivered",
"message.read",
"message.failed",
"message.echoed",
"message.updated",
"order.received",
"order.status_changed",
"order.cancelled",
"order.paid",
"sync.completed",
"stock.low",
"product.blocked",
"product.drifted",
"campaign.completed",
"campaign.failed",
"group.created",
"group.create_failed",
"group.updated",
"group.deleted",
"group.suspended",
"group.suspension_cleared",
"group.participant_joined",
"group.participant_left",
"group.participant_removed",
"group.join_requested",
"group.join_request_revoked",
"group.invite_sent",
"template.status_changed",
"form.submitted",
"form.status_changed",
"webhook.paused",
"cart.submitted",
"cart.abandoned",
"flow.session.started",
"flow.session.ended",
"lead.created",
"lead.updated",
"lead.stage_changed",
"lead.label_added",
"lead.label_removed",
"lead.note_added",
"lead.assigned",
"lead.merged",
"lead.deleted",
"voice.otp.answered",
"voice.otp.completed",
"voice.otp.failed",
"voice.message.answered",
"voice.message.completed",
"voice.message.failed",
"call.completed",
"call.recording_ready",
"call.feedback_ready",
"call_campaign.started",
"call_campaign.target_completed",
"call_campaign.paused",
"call_campaign.resumed",
"call_campaign.completed",
"call_campaign.failed",
"webhook.test"
]
},
"timestamp": {
"type": "string",
"description": "Dispatch time in ISO8601.",
"format": "date-time"
},
"message_id": {
"type": "integer",
"description": "Message events: local numeric message ID, usable in SMS/WhatsApp lookup."
},
"direction": {
"type": "string",
"description": "Message direction.",
"enum": [
"inbound",
"outbound"
]
},
"sender": {
"type": [
"string",
"null"
],
"description": "Message sender identity."
},
"recipient": {
"type": "string",
"description": "Message recipient identity."
},
"status": {
"type": "string",
"description": "Message delivery state."
},
"body": {
"type": [
"string",
"null"
],
"description": "Message body."
},
"media_url": {
"type": [
"string",
"null"
],
"description": "Attached media URL."
},
"channel_type": {
"type": [
"string",
"null"
],
"description": "Message channel type."
},
"order_id": {
"type": "integer",
"description": "Order events: local order ID."
},
"customer_wa_id": {
"type": "string",
"description": "order.received: customer WhatsApp identifier."
},
"customer_name": {
"type": [
"string",
"null"
],
"description": "order.received: customer name."
},
"product_items": {
"type": "array",
"description": "order.received: incoming cart items.",
"items": {
"$ref": "#/components/schemas/OrderItem"
}
},
"total_amount": {
"type": "integer",
"description": "order.received: total in integer hundredths."
},
"total_currency": {
"type": "string",
"description": "order.received: currency code."
},
"customer_note": {
"type": [
"string",
"null"
],
"description": "order.received: customer note."
},
"conversation_id": {
"type": [
"integer",
"null"
],
"description": "Order event: linked conversation ID."
},
"created_at": {
"type": "string",
"description": "order.received: creation time.",
"format": "date-time"
},
"payment_id": {
"type": "integer",
"description": "order.paid: payment ID."
},
"method": {
"type": "string",
"description": "order.paid: payment method."
},
"amount_minor": {
"type": "integer",
"description": "order.paid: paid amount in minor units."
},
"currency": {
"type": "string",
"description": "order.paid: currency code."
},
"payer_msisdn": {
"type": [
"string",
"null"
],
"description": "order.paid: payer phone number."
},
"paid_at": {
"type": [
"string",
"null"
],
"description": "order.paid: settlement time.",
"format": "date-time"
},
"group": {
"$ref": "#/components/schemas/WhatsAppGroup",
"description": "Current local WhatsApp group summary, when the event concerns a group."
},
"wa_ids": {
"type": "array",
"description": "Participant event: affected WhatsApp IDs.",
"items": {
"type": "string"
}
},
"reason": {
"type": [
"string",
"null"
],
"description": "Participant event reason when supplied. lead.stage_changed: the reason given for lost or unqualified."
},
"applied": {
"type": "object",
"description": "group.updated: applied settings.",
"additionalProperties": true
},
"errors": {
"type": [
"array",
"object",
"null"
],
"description": "Provider/group error details.",
"items": [],
"additionalProperties": true
},
"sent": {
"type": [
"integer",
"array"
],
"description": "group.invite_sent: successfully sent invitations.",
"items": []
},
"failed": {
"type": [
"integer",
"array"
],
"description": "group.invite_sent: failed invitations.",
"items": []
},
"template_id": {
"type": "integer",
"description": "template.status_changed: local template id, for `GET /api/v3/whatsapp/templates/{template}`."
},
"name": {
"type": "string",
"description": "template.status_changed: the template name."
},
"language": {
"type": "string",
"description": "template.status_changed: the template language."
},
"whatsapp_business_account_id": {
"type": "string",
"description": "template.status_changed: the WhatsApp Business Account whose review moved."
},
"whatsapp_template_id": {
"type": [
"string",
"null"
],
"description": "template.status_changed: Meta's id on that account."
},
"previous_status": {
"type": [
"string",
"null"
],
"description": "template.status_changed: the status before this change."
},
"whatsapp_status": {
"type": "string",
"description": "template.status_changed: the status now.",
"enum": [
"pending",
"in_review",
"approved",
"rejected",
"disabled",
"paused"
]
},
"rejection_reason": {
"type": [
"string",
"null"
],
"description": "template.status_changed: Meta's reason when the new status is rejected."
},
"event_id": {
"type": "string",
"description": "This event's id: `evt_` + a ULID. The same on every retry and replay and on every endpoint that receives the event \u2014 dedupe on this (also sent as `X-Event-Id`)."
},
"lead": {
"$ref": "#/components/schemas/LeadWebhookSnapshot",
"description": "lead.* events: the whole lead as it is now."
},
"changes": {
"type": "object",
"description": "lead.updated, lead.stage_changed, lead.assigned: `{field: {from, to}}`. A burst of updates within about five seconds arrives as one lead.updated with the changes folded together.",
"additionalProperties": true
},
"actor": {
"type": "object",
"description": "lead.* events: who made the change.",
"properties": {
"kind": {
"type": "string",
"description": "user, ai, mcp, api, flow, form, import or system."
},
"id": {
"type": [
"integer",
"null"
],
"description": "The person, AI agent or credential id, when there is one."
},
"label": {
"type": [
"string",
"null"
],
"description": "Their name at the time."
}
}
},
"source": {
"type": [
"object",
"null"
],
"description": "lead.* events: the call or conversation the change happened in, if any.",
"properties": {
"kind": {
"type": "string",
"description": "call, conversation, comment, form_answer, email or contact."
},
"id": {
"type": "string",
"description": "That record's id, as a string."
},
"channel": {
"type": [
"string",
"null"
],
"description": "Its channel."
}
}
},
"label": {
"type": "object",
"description": "lead.label_added / lead.label_removed: the label.",
"properties": {
"name": {
"type": "string",
"description": "Label name."
},
"color": {
"type": "string",
"description": "Hex colour."
}
}
},
"note": {
"type": "object",
"description": "lead.note_added: the note.",
"properties": {
"body": {
"type": "string",
"description": "The note text."
},
"author": {
"type": [
"string",
"null"
],
"description": "Who wrote it."
}
}
},
"merged_id": {
"type": "string",
"description": "lead.merged: the id of the lead that was merged into `lead` and no longer exists.",
"format": "uuid"
},
"test": {
"type": "boolean",
"description": "webhook.test and any sample sent with the Test button: true. Never set on a real event."
},
"message": {
"type": "string",
"description": "webhook.test: a sentence saying what this is."
},
"call": {
"$ref": "#/components/schemas/Call",
"description": "call.*: the call (the same object GET /api/v3/calls/{id} returns). call.* events are sent only for calls a call campaign or POST /api/v3/calls placed."
},
"campaign": {
"type": "object",
"description": "call_campaign.*: the campaign (the same object GET /api/v3/call-campaigns/{id} returns); on call_campaign.target_completed only its id, name, external_ref and is_rolling.",
"additionalProperties": true
},
"target": {
"$ref": "#/components/schemas/CallCampaignTarget",
"description": "call_campaign.target_completed: the person, echoing your external_id and variables."
},
"recording": {
"type": "object",
"description": "call.recording_ready: the recording.",
"properties": {
"id": {
"type": [
"integer",
"null"
],
"description": "The recording id."
},
"duration_seconds": {
"type": [
"integer",
"null"
],
"description": "Length."
},
"status": {
"type": "string",
"description": "complete \u2026"
},
"list_url": {
"type": "string",
"description": "GET it with your key for the audio link."
}
}
},
"feedback": {
"type": "object",
"description": "call.feedback_ready: the AI's summary of the call.",
"properties": {
"summary": {
"type": [
"string",
"null"
],
"description": "One-paragraph summary."
},
"sentiment": {
"type": [
"string",
"null"
],
"description": "positive, neutral or negative."
},
"disposition": {
"type": [
"string",
"null"
],
"description": "How the call ended, in the AI's words."
},
"key_topics": {
"type": "array",
"description": "Topics raised.",
"items": {
"type": "string",
"description": "A topic."
}
},
"action_items": {
"type": "array",
"description": "Things to do.",
"items": {
"type": "string",
"description": "An action."
}
},
"next_best_action": {
"type": [
"string",
"null"
],
"description": "What to do next."
}
}
},
"answers": {
"type": "object",
"description": "call.feedback_ready on a campaign call: the person's answers so far.",
"additionalProperties": true
},
"state": {
"type": "string",
"description": "call_campaign.completed: finished (everyone called) or stopped (ended early)."
},
"automatic": {
"type": "boolean",
"description": "call_campaign.paused / .resumed: the campaign did it by itself (wallet low, needs attention, wallet topped up)."
},
"top_up": {
"type": "number",
"description": "call_campaign.paused with reason wallet_low: how much to top up to continue."
},
"attention_reason": {
"type": "string",
"description": "call_campaign.paused with reason needs_attention: caller_number_disabled, agent_deleted, ivr_unpublished, pbx_unreachable or message_invalid."
},
"campaign_uid": {
"type": "string",
"description": "campaign.completed / campaign.failed: the SMS campaign."
},
"recipients": {
"type": "integer",
"description": "campaign.completed: people the SMS campaign went to."
},
"channel": {
"type": "string",
"description": "campaign.completed / campaign.failed: sms or whatsapp."
}
},
"required": [
"event",
"timestamp"
],
"description": "Actual flat ChannelWebhook payload. Every body carries `event`, `event_id` and `timestamp`. Message events include message_id/direction/sender/recipient/status/body/media_url/channel_type. Orders, groups and leads supply their own fields \u2014 a `lead.*` event carries the full `lead`, plus `changes`, `actor` and, when it happened in a call or chat, `source`. No data wrapper, tenant_id or occurred_at is added by this dispatcher."
}
A message arrived
{
"event": "message.received",
"message_id": 101,
"direction": "inbound",
"sender": "255712345678",
"recipient": "MyBrand",
"status": "received",
"body": "Habari, mna kanga?",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message was sent
{
"event": "message.sent",
"message_id": 102,
"direction": "outbound",
"sender": "MyBrand",
"recipient": "255712345678",
"status": "sent",
"body": "Ndiyo, tuna kanga.",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message was delivered
{
"event": "message.delivered",
"message_id": 102,
"direction": "outbound",
"sender": "MyBrand",
"recipient": "255712345678",
"status": "delivered",
"body": "Ndiyo, tuna kanga.",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message was read
{
"event": "message.read",
"message_id": 102,
"direction": "outbound",
"sender": "MyBrand",
"recipient": "255712345678",
"status": "read",
"body": "Ndiyo, tuna kanga.",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message failed
{
"event": "message.failed",
"message_id": 103,
"direction": "outbound",
"sender": "MyBrand",
"recipient": "255712345678",
"status": "failed",
"body": "Ofa ya leo!",
"media_url": null,
"channel_type": "sms",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message was sent from the phone itself
{
"event": "message.echoed",
"message_id": 104,
"direction": "outbound",
"sender": "MyBrand",
"recipient": "255712345678",
"status": "sent",
"body": "Karibu!",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A message was edited
{
"event": "message.updated",
"message_id": 101,
"direction": "inbound",
"sender": "255712345678",
"recipient": "MyBrand",
"status": "received",
"body": "Habari, mna kanga za bluu?",
"media_url": null,
"channel_type": "whatsapp",
"timestamp": "2026-09-11T09:14:02+00:00"
}
An order arrived
{
"event": "order.received",
"order": {
"id": 9182,
"catalogue_id": 42,
"platform": "whatsapp",
"status": "pending",
"needs_attention": false,
"stock_policy": "external",
"customer_handle": "255712345678",
"customer_name": "Asha Mrisho",
"customer_phone": "255712345678",
"customer_note": null,
"lines": [
{
"sku": "MNG-45W",
"name": "Charger Mango 45W",
"quantity": 1,
"unit_price_minor": 3900000,
"line_total_minor": 3900000,
"currency": "TZS",
"reserved": 1,
"stock_short": false,
"unresolved": false
}
],
"total_minor": 3900000,
"currency": "TZS",
"conversation_id": 771,
"priced_at": "2026-09-11T09:14:02+00:00",
"created_at": "2026-09-11T09:14:02+00:00",
"order_id": 9182,
"customer_wa_id": "255712345678",
"total_amount": 3900000,
"total_currency": "TZS"
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
An order changed status
{
"event": "order.status_changed",
"order": {
"id": 9182,
"catalogue_id": 42,
"platform": "whatsapp",
"status": "confirmed",
"needs_attention": false,
"stock_policy": "external",
"customer_handle": "255712345678",
"customer_name": "Asha Mrisho",
"customer_phone": "255712345678",
"customer_note": null,
"lines": [
{
"sku": "MNG-45W",
"name": "Charger Mango 45W",
"quantity": 1,
"unit_price_minor": 3900000,
"line_total_minor": 3900000,
"currency": "TZS",
"reserved": 1,
"stock_short": false,
"unresolved": false
}
],
"total_minor": 3900000,
"currency": "TZS",
"conversation_id": 771,
"priced_at": "2026-09-11T09:14:02+00:00",
"created_at": "2026-09-11T09:14:02+00:00",
"order_id": 9182,
"customer_wa_id": "255712345678",
"total_amount": 3900000,
"total_currency": "TZS"
},
"previous_status": "pending",
"timestamp": "2026-09-11T09:14:02+00:00"
}
An order was cancelled
{
"event": "order.cancelled",
"order": {
"id": 9182,
"catalogue_id": 42,
"platform": "whatsapp",
"status": "cancelled",
"needs_attention": false,
"stock_policy": "external",
"customer_handle": "255712345678",
"customer_name": "Asha Mrisho",
"customer_phone": "255712345678",
"customer_note": null,
"lines": [
{
"sku": "MNG-45W",
"name": "Charger Mango 45W",
"quantity": 1,
"unit_price_minor": 3900000,
"line_total_minor": 3900000,
"currency": "TZS",
"reserved": 1,
"stock_short": false,
"unresolved": false
}
],
"total_minor": 3900000,
"currency": "TZS",
"conversation_id": 771,
"priced_at": "2026-09-11T09:14:02+00:00",
"created_at": "2026-09-11T09:14:02+00:00",
"order_id": 9182,
"customer_wa_id": "255712345678",
"total_amount": 3900000,
"total_currency": "TZS"
},
"previous_status": "pending",
"timestamp": "2026-09-11T09:14:02+00:00"
}
An order was paid
{
"event": "order.paid",
"order_id": 9182,
"payment_id": 4410,
"method": "ussd_push",
"amount_minor": 3900000,
"currency": "TZS",
"payer_msisdn": "255712345678",
"paid_at": "2026-09-11T09:14:02+00:00",
"conversation_id": 771,
"timestamp": "2026-09-11T09:14:02+00:00"
}
A bulk sync finished
{
"event": "sync.completed",
"sync": {
"id": 812,
"catalogue_id": 42,
"source": "api",
"mode": "upsert",
"status": "completed",
"received": 2000,
"created": 12,
"updated": 1982,
"unchanged": 0,
"rejected": 6,
"retired": 0,
"platforms": {
"whatsapp": {
"synced": 1960,
"blocked": 34
}
},
"problems_truncated": false
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A product is running low
{
"event": "stock.low",
"catalogue_id": 42,
"sku": "MNG-45W",
"name": "Charger Mango 45W",
"available": 2,
"threshold": 3,
"timestamp": "2026-09-11T09:14:02+00:00"
}
A platform will not show a product
{
"event": "product.blocked",
"catalogue_id": 42,
"sku": "MNG-KNIFE",
"platform": "whatsapp",
"problem": "WhatsApp needs a product image it can fetch.",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A platform's copy of a product differs from ours
{
"event": "product.drifted",
"catalogue_id": 42,
"sku": "MNG-45W",
"platform": "whatsapp",
"source_of_truth": "api",
"diff": {
"price": {
"ours": 4500000,
"theirs": 4200000
}
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A campaign finished
{
"event": "campaign.completed",
"campaign_uid": "cmp_8f2c",
"sent": 1180,
"failed": 20,
"timestamp": "2026-09-11T09:14:02+00:00"
}
A campaign failed
{
"event": "campaign.failed",
"campaign_uid": "cmp_8f2c",
"reason": "Insufficient balance.",
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group was created
{
"event": "group.created",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group could not be created
{
"event": "group.create_failed",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group was updated
{
"event": "group.updated",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group was deleted
{
"event": "group.deleted",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group was suspended by WhatsApp
{
"event": "group.suspended",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group suspension was lifted
{
"event": "group.suspension_cleared",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
Someone joined a group
{
"event": "group.participant_joined",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
Someone left a group
{
"event": "group.participant_left",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
Someone was removed from a group
{
"event": "group.participant_removed",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
Someone asked to join a group
{
"event": "group.join_requested",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A join request was withdrawn
{
"event": "group.join_request_revoked",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A group invite was sent
{
"event": "group.invite_sent",
"group": {
"id": 31,
"subject": "Wateja wa Dar",
"participants_count": 48
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
An endpoint was paused
{
"event": "webhook.paused",
"webhook_id": 7,
"url": "https://store.example.com/momo",
"consecutive_failures": 50,
"timestamp": "2026-09-11T09:14:02+00:00"
}
A flow session started
{
"event": "flow.session.started",
"session_id": 5120,
"flow_id": 17,
"flow_name": "Oda ya chakula",
"flow_version": 3,
"conversation_id": 771,
"contact_id": 2201,
"contact_name": "Asha Mrisho",
"contact_identifier": "255712345678",
"trigger": "inbound",
"status": "running",
"outcome": "in_progress",
"ended_reason": null,
"node_id": "ask_name",
"turns": 0,
"started_at": "2026-09-11T09:14:02+00:00",
"ended_at": null,
"variables": [],
"timestamp": "2026-09-11T09:14:02+00:00"
}
A flow session ended
{
"event": "flow.session.ended",
"session_id": 5120,
"flow_id": 17,
"flow_name": "Oda ya chakula",
"flow_version": 3,
"conversation_id": 771,
"contact_id": 2201,
"contact_name": "Asha Mrisho",
"contact_identifier": "255712345678",
"trigger": "inbound",
"status": "completed",
"outcome": "completed",
"ended_reason": "completed",
"node_id": "done",
"turns": 6,
"started_at": "2026-09-11T09:14:02+00:00",
"ended_at": "2026-09-11T09:14:02+00:00",
"variables": {
"order_ref": "ORD-2026-0091",
"total": 24000
},
"timestamp": "2026-09-11T09:14:02+00:00"
}
A lead moved stage
{
"event": "lead.stage_changed",
"event_id": "evt_01J8Z6Q4M3T8W5K2N7XQ4R9ABC",
"timestamp": "2026-09-25T14:03:11+03:00",
"lead": {
"id": "0199a2c4-6f1e-7c1a-9d2b-3c5e8f7a1b20",
"name": "Amina Juma",
"phone": "+255712345678",
"email": null,
"company": "Amina Shop",
"location": "Mbezi, Dar es Salaam",
"stage": "qualified",
"closed_at": null,
"archived_at": null,
"lost_reason": null,
"source_channel": "whatsapp",
"source_detail": "Ad: October solar promo",
"interest": "Solar kit 5 kW",
"estimated_value": 4500000,
"currency": "TZS",
"score": 72,
"score_reason": "Budget stated, wants install this month",
"summary": "Shop owner in Mbezi who needs backup power for two fridges. Budget about TSh 4.5M.",
"next_action": "Send quote",
"next_action_at": "2026-09-26T10:00:00+03:00",
"labels": [
"hot",
"follow-up"
],
"assigned_to": {
"id": 311,
"name": "Baraka M."
},
"custom_fields": {
"budget_band": "mid"
},
"created_by": {
"kind": "ai",
"id": 14
},
"created_at": "2026-09-24T09:12:40+03:00",
"updated_at": "2026-09-25T14:03:11+03:00",
"url": "https://business.momo.tz/app/leads/0199a2c4-6f1e-7c1a-9d2b-3c5e8f7a1b20"
},
"changes": {
"stage": {
"from": "contacted",
"to": "qualified"
}
},
"reason": null,
"actor": {
"kind": "ai",
"id": 14,
"label": "Mauzo AI"
},
"source": {
"kind": "conversation",
"id": "88213",
"channel": "whatsapp"
}
}
A campaign or API call ended
{
"event": "call.completed",
"event_id": "evt_call_completed_81234",
"call": {
"id": 81234,
"room_name": "out-7f3c2a",
"direction": "outbound",
"status": "ended",
"outcome": "answered",
"answered": true,
"from": "+255746000111",
"to": "+255712345678",
"mode": "message",
"agent_config_id": null,
"source": "api",
"started_at": "2026-10-07T10:00:00+03:00",
"answered_at": "2026-10-07T10:00:07+03:00",
"ended_at": "2026-10-07T10:00:31+03:00",
"duration_seconds": 24,
"sip_status_code": null,
"keys_pressed": [
{
"digit": "1",
"action": "confirm",
"label": "Thibitisha",
"at": "2026-10-07T07:00:21Z"
}
],
"recording_available": false,
"transcript_available": false,
"request": {
"external_ref": "order-A1023",
"purpose": null,
"variables": {
"jina": "Amina",
"oda": "A1023"
},
"estimated_cost": 87
},
"campaign": null
},
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call recording is ready
{
"event": "call.recording_ready",
"event_id": "evt_call_recording_81234_77",
"call": {
"id": 81234,
"room_name": "out-7f3c2a",
"direction": "outbound",
"status": "ended",
"outcome": "answered",
"answered": true,
"from": "+255746000111",
"to": "+255712345678",
"mode": "message",
"agent_config_id": null,
"source": "api",
"started_at": "2026-10-07T10:00:00+03:00",
"answered_at": "2026-10-07T10:00:07+03:00",
"ended_at": "2026-10-07T10:00:31+03:00",
"duration_seconds": 24,
"sip_status_code": null,
"keys_pressed": [
{
"digit": "1",
"action": "confirm",
"label": "Thibitisha",
"at": "2026-10-07T07:00:21Z"
}
],
"recording_available": false,
"transcript_available": false,
"request": {
"external_ref": "order-A1023",
"purpose": null,
"variables": {
"jina": "Amina",
"oda": "A1023"
},
"estimated_cost": 87
},
"campaign": null
},
"recording": {
"id": 77,
"duration_seconds": 24,
"status": "complete",
"list_url": "https://business.momo.tz/api/v3/calls/81234/recordings"
},
"timestamp": "2026-10-07T10:00:00+03:00"
}
An AI call summary is ready
{
"event": "call.feedback_ready",
"event_id": "evt_call_feedback_81234",
"call": {
"id": 81234,
"room_name": "out-7f3c2a",
"direction": "outbound",
"status": "ended",
"outcome": "answered",
"answered": true,
"from": "+255746000111",
"to": "+255712345678",
"mode": "ai",
"agent_config_id": null,
"source": "api",
"started_at": "2026-10-07T10:00:00+03:00",
"answered_at": "2026-10-07T10:00:07+03:00",
"ended_at": "2026-10-07T10:00:31+03:00",
"duration_seconds": 24,
"sip_status_code": null,
"keys_pressed": [
{
"digit": "1",
"action": "confirm",
"label": "Thibitisha",
"at": "2026-10-07T07:00:21Z"
}
],
"recording_available": false,
"transcript_available": false,
"request": {
"external_ref": "order-A1023",
"purpose": null,
"variables": {
"jina": "Amina",
"oda": "A1023"
},
"estimated_cost": 87
},
"campaign": null
},
"feedback": {
"summary": "Amina confirmed and wants delivery after 17:00.",
"sentiment": "positive",
"disposition": "confirmed",
"key_topics": [
"delivery time"
],
"action_items": [
"Deliver after 17:00"
],
"next_best_action": null
},
"answers": {
"confirmed": true
},
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call campaign started calling
{
"event": "call_campaign.started",
"event_id": "evt_ccev_901",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"goal": "confirm_orders",
"status": "running",
"state": "calling",
"state_label": "Calling",
"needs_attention": false,
"pause_reason": null,
"attention_reason": null,
"mode": "message",
"is_rolling": true,
"purpose_class": "transactional",
"source": "api",
"external_ref": "cod-confirmations",
"people": 120,
"counts": {
"all": 120,
"waiting": 14,
"calling": 2,
"reached": 31,
"pressed": 58,
"pressed_by_digit": {
"1": 51,
"2": 7
},
"reached_total": 89,
"callback": 0,
"not_reached": 15,
"opted_out": 0,
"wrong_number": 0,
"skipped": 0
},
"spent": 7743,
"held": 2088,
"likely_cost": 6264,
"currency": "TZS",
"message": {
"text": "Habari {jina}, tunathibitisha oda yako {oda} ya shilingi {kiasi}. Bonyeza 1 kuthibitisha, 2 kuighairi. Bonyeza 9 tusikupigie tena.",
"audio_asset_id": null,
"voice_id": null,
"voice_model": null,
"language": "sw",
"repeat": 1
},
"keys": {
"1": {
"action": "confirm",
"label": "Thibitisha"
},
"2": {
"action": "tag",
"label": "Ghairi",
"tag": "cancelled_order"
},
"9": {
"action": "opt_out",
"label": "Usipigiwe tena / Stop calling me"
}
},
"ivr_flow_id": null,
"agent_config_id": null,
"answer_fields": [],
"settings": {
"calling_window": {
"timezone": "Africa/Dar_es_Salaam",
"days": [
1,
2,
3,
4,
5,
6
],
"from": "08:00",
"to": "20:00",
"enforced": true
},
"max_tries": 3,
"ring_seconds": 30,
"lines": null,
"from_number": null,
"stop_rule": "call_everyone",
"max_call_seconds": 90,
"record_calls": false,
"cooldown_hours": 0,
"budget_cap": null
},
"connections": {
"leads": {
"answer_key": "interested",
"stage": "qualified",
"note": true
}
},
"scheduled_at": null,
"started_at": "2026-10-07T10:00:00+03:00",
"paused_at": null,
"finished_at": null,
"created_at": "2026-10-07T10:00:00+03:00",
"updated_at": "2026-10-07T10:00:00+03:00"
},
"timestamp": "2026-10-07T10:00:00+03:00"
}
A person's calls are done
{
"event": "call_campaign.target_completed",
"event_id": "evt_cctg_5501_3f9a1c2b7d",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"external_ref": "cod-confirmations",
"is_rolling": true
},
"target": {
"id": 5501,
"position": 87,
"to": "+255712345678",
"name": "Amina J.",
"external_id": "order-A1023",
"contact_id": null,
"result": "pressed",
"result_label": "Pressed 1",
"final": true,
"tries": 1,
"max_tries": 3,
"next_try_at": null,
"keys_pressed": [
"1"
],
"answers": {
"confirmed": true
},
"summary": null,
"variables": {
"jina": "Amina J.",
"oda": "A1023",
"kiasi": "45,000"
},
"last_call_id": 81234,
"last_call_at": "2026-10-07T10:00:00+03:00",
"cost": 87,
"created_at": "2026-10-07T10:00:00+03:00"
},
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call campaign paused
{
"event": "call_campaign.paused",
"event_id": "evt_ccev_902",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"goal": "confirm_orders",
"status": "paused",
"state": "paused",
"state_label": "Paused",
"needs_attention": false,
"pause_reason": "wallet_low",
"attention_reason": null,
"mode": "message",
"is_rolling": true,
"purpose_class": "transactional",
"source": "api",
"external_ref": "cod-confirmations",
"people": 120,
"counts": {
"all": 120,
"waiting": 14,
"calling": 2,
"reached": 31,
"pressed": 58,
"pressed_by_digit": {
"1": 51,
"2": 7
},
"reached_total": 89,
"callback": 0,
"not_reached": 15,
"opted_out": 0,
"wrong_number": 0,
"skipped": 0
},
"spent": 7743,
"held": 2088,
"likely_cost": 6264,
"currency": "TZS",
"message": {
"text": "Habari {jina}, tunathibitisha oda yako {oda} ya shilingi {kiasi}. Bonyeza 1 kuthibitisha, 2 kuighairi. Bonyeza 9 tusikupigie tena.",
"audio_asset_id": null,
"voice_id": null,
"voice_model": null,
"language": "sw",
"repeat": 1
},
"keys": {
"1": {
"action": "confirm",
"label": "Thibitisha"
},
"2": {
"action": "tag",
"label": "Ghairi",
"tag": "cancelled_order"
},
"9": {
"action": "opt_out",
"label": "Usipigiwe tena / Stop calling me"
}
},
"ivr_flow_id": null,
"agent_config_id": null,
"answer_fields": [],
"settings": {
"calling_window": {
"timezone": "Africa/Dar_es_Salaam",
"days": [
1,
2,
3,
4,
5,
6
],
"from": "08:00",
"to": "20:00",
"enforced": true
},
"max_tries": 3,
"ring_seconds": 30,
"lines": null,
"from_number": null,
"stop_rule": "call_everyone",
"max_call_seconds": 90,
"record_calls": false,
"cooldown_hours": 0,
"budget_cap": null
},
"connections": {
"leads": {
"answer_key": "interested",
"stage": "qualified",
"note": true
}
},
"scheduled_at": null,
"started_at": "2026-10-07T10:00:00+03:00",
"paused_at": null,
"finished_at": null,
"created_at": "2026-10-07T10:00:00+03:00",
"updated_at": "2026-10-07T10:00:00+03:00"
},
"reason": "wallet_low",
"automatic": true,
"top_up": 6000,
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call campaign resumed
{
"event": "call_campaign.resumed",
"event_id": "evt_ccev_903",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"goal": "confirm_orders",
"status": "running",
"state": "calling",
"state_label": "Calling",
"needs_attention": false,
"pause_reason": null,
"attention_reason": null,
"mode": "message",
"is_rolling": true,
"purpose_class": "transactional",
"source": "api",
"external_ref": "cod-confirmations",
"people": 120,
"counts": {
"all": 120,
"waiting": 14,
"calling": 2,
"reached": 31,
"pressed": 58,
"pressed_by_digit": {
"1": 51,
"2": 7
},
"reached_total": 89,
"callback": 0,
"not_reached": 15,
"opted_out": 0,
"wrong_number": 0,
"skipped": 0
},
"spent": 7743,
"held": 2088,
"likely_cost": 6264,
"currency": "TZS",
"message": {
"text": "Habari {jina}, tunathibitisha oda yako {oda} ya shilingi {kiasi}. Bonyeza 1 kuthibitisha, 2 kuighairi. Bonyeza 9 tusikupigie tena.",
"audio_asset_id": null,
"voice_id": null,
"voice_model": null,
"language": "sw",
"repeat": 1
},
"keys": {
"1": {
"action": "confirm",
"label": "Thibitisha"
},
"2": {
"action": "tag",
"label": "Ghairi",
"tag": "cancelled_order"
},
"9": {
"action": "opt_out",
"label": "Usipigiwe tena / Stop calling me"
}
},
"ivr_flow_id": null,
"agent_config_id": null,
"answer_fields": [],
"settings": {
"calling_window": {
"timezone": "Africa/Dar_es_Salaam",
"days": [
1,
2,
3,
4,
5,
6
],
"from": "08:00",
"to": "20:00",
"enforced": true
},
"max_tries": 3,
"ring_seconds": 30,
"lines": null,
"from_number": null,
"stop_rule": "call_everyone",
"max_call_seconds": 90,
"record_calls": false,
"cooldown_hours": 0,
"budget_cap": null
},
"connections": {
"leads": {
"answer_key": "interested",
"stage": "qualified",
"note": true
}
},
"scheduled_at": null,
"started_at": "2026-10-07T10:00:00+03:00",
"paused_at": null,
"finished_at": null,
"created_at": "2026-10-07T10:00:00+03:00",
"updated_at": "2026-10-07T10:00:00+03:00"
},
"automatic": true,
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call campaign ended
{
"event": "call_campaign.completed",
"event_id": "evt_ccev_904",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"goal": "confirm_orders",
"status": "cancelled",
"state": "stopped",
"state_label": "Stopped",
"needs_attention": false,
"pause_reason": null,
"attention_reason": null,
"mode": "message",
"is_rolling": true,
"purpose_class": "transactional",
"source": "api",
"external_ref": "cod-confirmations",
"people": 120,
"counts": {
"all": 120,
"waiting": 14,
"calling": 2,
"reached": 31,
"pressed": 58,
"pressed_by_digit": {
"1": 51,
"2": 7
},
"reached_total": 89,
"callback": 0,
"not_reached": 15,
"opted_out": 0,
"wrong_number": 0,
"skipped": 0
},
"spent": 7743,
"held": 2088,
"likely_cost": 6264,
"currency": "TZS",
"message": {
"text": "Habari {jina}, tunathibitisha oda yako {oda} ya shilingi {kiasi}. Bonyeza 1 kuthibitisha, 2 kuighairi. Bonyeza 9 tusikupigie tena.",
"audio_asset_id": null,
"voice_id": null,
"voice_model": null,
"language": "sw",
"repeat": 1
},
"keys": {
"1": {
"action": "confirm",
"label": "Thibitisha"
},
"2": {
"action": "tag",
"label": "Ghairi",
"tag": "cancelled_order"
},
"9": {
"action": "opt_out",
"label": "Usipigiwe tena / Stop calling me"
}
},
"ivr_flow_id": null,
"agent_config_id": null,
"answer_fields": [],
"settings": {
"calling_window": {
"timezone": "Africa/Dar_es_Salaam",
"days": [
1,
2,
3,
4,
5,
6
],
"from": "08:00",
"to": "20:00",
"enforced": true
},
"max_tries": 3,
"ring_seconds": 30,
"lines": null,
"from_number": null,
"stop_rule": "call_everyone",
"max_call_seconds": 90,
"record_calls": false,
"cooldown_hours": 0,
"budget_cap": null
},
"connections": {
"leads": {
"answer_key": "interested",
"stage": "qualified",
"note": true
}
},
"scheduled_at": null,
"started_at": "2026-10-07T10:00:00+03:00",
"paused_at": null,
"finished_at": "2026-10-07T10:00:00+03:00",
"created_at": "2026-10-07T10:00:00+03:00",
"updated_at": "2026-10-07T10:00:00+03:00"
},
"state": "stopped",
"timestamp": "2026-10-07T10:00:00+03:00"
}
A call campaign could not run
{
"event": "call_campaign.failed",
"event_id": "evt_ccev_905",
"campaign": {
"id": "01928c3e-7a1b-7c2d-9e0f-123456789abc",
"name": "Confirm orders",
"goal": "confirm_orders",
"status": "failed",
"state": "finished",
"state_label": "Finished",
"needs_attention": false,
"pause_reason": null,
"attention_reason": null,
"mode": "message",
"is_rolling": true,
"purpose_class": "transactional",
"source": "api",
"external_ref": "cod-confirmations",
"people": 120,
"counts": {
"all": 120,
"waiting": 14,
"calling": 2,
"reached": 31,
"pressed": 58,
"pressed_by_digit": {
"1": 51,
"2": 7
},
"reached_total": 89,
"callback": 0,
"not_reached": 15,
"opted_out": 0,
"wrong_number": 0,
"skipped": 0
},
"spent": 7743,
"held": 2088,
"likely_cost": 6264,
"currency": "TZS",
"message": {
"text": "Habari {jina}, tunathibitisha oda yako {oda} ya shilingi {kiasi}. Bonyeza 1 kuthibitisha, 2 kuighairi. Bonyeza 9 tusikupigie tena.",
"audio_asset_id": null,
"voice_id": null,
"voice_model": null,
"language": "sw",
"repeat": 1
},
"keys": {
"1": {
"action": "confirm",
"label": "Thibitisha"
},
"2": {
"action": "tag",
"label": "Ghairi",
"tag": "cancelled_order"
},
"9": {
"action": "opt_out",
"label": "Usipigiwe tena / Stop calling me"
}
},
"ivr_flow_id": null,
"agent_config_id": null,
"answer_fields": [],
"settings": {
"calling_window": {
"timezone": "Africa/Dar_es_Salaam",
"days": [
1,
2,
3,
4,
5,
6
],
"from": "08:00",
"to": "20:00",
"enforced": true
},
"max_tries": 3,
"ring_seconds": 30,
"lines": null,
"from_number": null,
"stop_rule": "call_everyone",
"max_call_seconds": 90,
"record_calls": false,
"cooldown_hours": 0,
"budget_cap": null
},
"connections": {
"leads": {
"answer_key": "interested",
"stage": "qualified",
"note": true
}
},
"scheduled_at": null,
"started_at": "2026-10-07T10:00:00+03:00",
"paused_at": null,
"finished_at": null,
"created_at": "2026-10-07T10:00:00+03:00",
"updated_at": "2026-10-07T10:00:00+03:00"
},
"reason": "client_not_found",
"timestamp": "2026-10-07T10:00:00+03:00"
}
The Test button
{
"event": "webhook.test",
"event_id": "evt_01J8Z7A0B1C2D3E4F5G6H7J8KM",
"timestamp": "2026-09-25T14:03:11+03:00",
"test": true,
"message": "A test from Momo Business. Answer 2xx and this endpoint is working."
}