Webhooks

Events & payloads

The exact requests Daffy Voice sends to your server: the call.result event from a workflow's Send results step, and the end-of-call and prefetch webhooks set on an AI employee.

call.result

Sent by a workflow's Send results step, once per call attempt that the step is set to report. See Send results to your tools for setup.

Headers

Request headers
POST /ubiq/results HTTP/1.1
Content-Type: application/json
User-Agent: UBIQ-Workflows/1
X-Ubiq-Signature: t=1791625380,v1=5f1c3e0a9b7d2c4e6f8a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e

X-Ubiq-Signature is present only when the step has a signing secret. See Verifying signatures.

Example: answered call

call.result
{
  "event": "call.result",
  "workflow": { "id": "8d0f6a52-3c1e-4b7a-9e21-5f4c3b2a1d0e", "name": "October EMI reminders" },
  "run_id": "c2b9e7a1-0f3d-4c6b-8a5e-7d1f2e3c4b5a",
  "call_id": "4a7e1c9b-2d3f-4e5a-8b6c-0d1e2f3a4b5c",
  "called_at": "2026-10-10T09:42:17.512340+00:00",
  "attempt": 1,
  "contact": {
    "name": "Rahul Sharma",
    "phone": "+919876543210",
    "loan_id": "LN-20417",
    "amount_due": "4500"
  },
  "result": {
    "answered": true,
    "outcome": "Promised to pay",
    "outcome_key": "promise_to_pay",
    "call_status": "completed",
    "note": "Salary is delayed this month; will pay on the 15th.",
    "objection": "salary delayed",
    "promise_date": "2026-10-15",
    "promise_amount": 4500,
    "callback_at": null,
    "details": { "Preferred payment method": "UPI" },
    "summary": "Rahul confirmed the EMI and promised to pay ₹4,500 by 15 October via UPI.",
    "duration_sec": 74
  },
  "row": {
    "Called at": "2026-10-10T09:42:17.512340+00:00",
    "Name": "Rahul Sharma",
    "Phone": "+919876543210",
    "Answered": "Yes",
    "Outcome": "Promised to pay",
    "Note": "Salary is delayed this month; will pay on the 15th.",
    "Promise date": "2026-10-15",
    "Promise amount": 4500,
    "Callback at": "",
    "Preferred payment method": "UPI",
    "Duration (sec)": 74,
    "Workflow": "October EMI reminders"
  }
}

Example: no answer

call.result
{
  "event": "call.result",
  "workflow": { "id": "8d0f6a52-3c1e-4b7a-9e21-5f4c3b2a1d0e", "name": "October EMI reminders" },
  "run_id": "c2b9e7a1-0f3d-4c6b-8a5e-7d1f2e3c4b5a",
  "call_id": "9b3c5d7e-1f2a-4b6c-8d0e-2f4a6b8c0d1e",
  "called_at": "2026-10-10T09:44:03.118201+00:00",
  "attempt": 2,
  "contact": { "name": "Priya Nair", "phone": "+919812345678" },
  "result": {
    "answered": false,
    "outcome": null,
    "outcome_key": null,
    "call_status": "no_answer",
    "note": null,
    "objection": null,
    "promise_date": null,
    "promise_amount": null,
    "callback_at": null,
    "details": {},
    "summary": null,
    "duration_sec": null
  },
  "row": {
    "Called at": "2026-10-10T09:44:03.118201+00:00",
    "Name": "Priya Nair",
    "Phone": "+919812345678",
    "Answered": "No",
    "Outcome": "no_answer",
    "Note": "",
    "Promise date": "",
    "Promise amount": "",
    "Callback at": "",
    "Duration (sec)": "",
    "Workflow": "October EMI reminders"
  }
}

Top-level fields

eventstring
Always call.result.
workflowobject
The workflow's id and name.
run_idstring
The ID of the workflow's calling run. test for a test delivery.
call_idstring | null
The call's ID, matching the call in Call logs. null when no call was placed, and for a test delivery.
called_atstring | null
When the call started (ISO 8601, UTC).
attemptinteger
Which dial attempt this was for the contact: 1 for the first call, 2 for the first retry, and so on. It is not a delivery retry counter.
contactobject
Every field from your list or API request (values as text; fields starting with _ are removed), plus name and phone.
resultobject
The structured result — see below.
rowobject
The same result as one flat row of column → value — see below.
testboolean
Present and true only on deliveries from Send a test.

result

answeredboolean
True when the call connected and has a duration. False for no answer, busy, voicemail, machine, failed, cancelled and dial errors.
outcomestring | null
The outcome label from your workflow, e.g. Promised to pay. null when the call wasn't classified (usually unanswered calls).
outcome_keystring | null
The outcome's stable key, e.g. promise_to_pay. Use this in code; labels can be renamed.
call_statusstring | null
How the attempt ended, e.g. completed, no_answer, busy, voicemail, failed. If a workflow action already re-queued the contact, it can read requeued.
notestring | null
A short note from the AI's review of the call.
objectionstring | null
A 1–4 word objection the person raised, e.g. too expensive.
promise_datestring | null
Date the person committed to pay by, YYYY-MM-DD.
promise_amountnumber | null
Amount the person committed to pay.
callback_atstring | null
When the person asked to be called back, YYYY-MM-DDTHH:MM in the workflow's local time.
detailsobject
Details your AI employee captured (set in Outcomes & captured details), keyed by label. Empty values are left out.
summarystring | null
A one- or two-sentence summary of the call.
duration_secinteger | null
Call length in seconds.

row

columnsobject
In this order: Called at, Name, Phone, Answered (Yes/No), Outcome (the label, or the call status when there is none), Note, Promise date, Promise amount, Callback at, one column per captured detail, Duration (sec), Workflow. Missing values are empty strings.

Timing

For answered calls, Daffy Voice waits for the transcript and the AI review before sending, so the result usually arrives shortly after the call ends. Unanswered attempts are sent immediately. A contact who is retried produces one call.result per attempt the step reports.

End-of-call

Sent by an AI employee with an End-of-Call Webhook URL, after every call it handles — inbound, outbound, workflow and website widget calls alike.

  • Method POST, header Content-Type: application/json.
  • No signature header and no event name in the body.
end-of-call
{
  "call_id": "4a7e1c9b-2d3f-4e5a-8b6c-0d1e2f3a4b5c",
  "duration_sec": 74.3,
  "transcript": [
    { "role": "agent", "text": "Hi Rahul, this is Riya from Acme Finance. Is this a good time?" },
    { "role": "user", "text": "Yes, go ahead." },
    { "role": "agent", "text": "Your EMI of ₹4,500 was due on the 5th. When can you pay it?" },
    { "role": "user", "text": "By the 15th, my salary is late." }
  ],
  "outcome": "neutral"
}

Fields

call_idstring
The call's ID.
duration_secnumber
Call length in seconds, to one decimal place.
transcriptobject[]
The conversation in order. Each turn has role — user (the caller) or agent (your AI employee) — and text.
outcomestring
voicemail when the call reached voicemail; otherwise the caller's overall sentiment: positive, neutral or negative. This is not the workflow outcome — use call.result for that.

Prefetch data

Sent by an AI employee with a Prefetch Data Webhook URL, before each conversation starts.

Request
GET https://crm.example.com/ubiq/prefetch?caller_id=%2B919876543210

Query parameters

caller_idstring
The other party's number in international format, unknown when it isn't available, or web for website widget calls.

Respond with 2xx and any JSON object. Its contents are added to the AI employee's instructions for that call. Details and limits are in the overview.