Skip to content

Results

result is present on every terminal order, including ones where nobody answered and ones that were cancelled before a single dial. It is the one place a client looks to find out how an order turned out. It is absent only while the order is still running.

Nothing in a result is classified by a second language model. Every field is derived from what the voice runtime recorded when the call ended. Two models judging the same conversation differently, with no way to say which was right, is not a foundation to put a case file on.

{
"result": {
"reachability": "reached",
"engagement": "conversation",
"identity": { "verified": true, "method": "address_birthday", "attempts": 1 },
"termination": { "actor": "subject", "reason": "completed" },
"summary_code": "payment_promised",
"summary_code_raw": null,
"outcomes": [
{ "type": "payment_promise",
"data": { "amount": { "value": "129.90", "currency": "EUR" },
"due_date": "2026-09-15" } }
],
"summary_text": "Debtor acknowledged the claim and promised payment by 15 September."
}
}

One value, deliberately, so a typed client has exactly one thing to switch on.

Value
payment_promised A promise to pay was given.
payment_claimed The debtor says they already paid.
payment_link_sent A payment link was sent during the call.
installment_plan_requested An instalment plan was asked for and recorded.
unable_to_pay Inability to pay was stated.
refused Payment was refused.
dispute The claim itself was contested.
callback A callback was requested.
escalated Handed to a human.
info_provided Information was given, nothing else concluded.
no_answer Nobody reached.
wrong_number The number does not belong to the subject.
not_debtor Someone else answered.
identity_failed Identification did not succeed.
abusive The agent ended the call on conduct grounds.
unresolved A conversation happened and settled nothing.
other Something outside the registry.
canceled The order was cancelled.
expired The window passed.
platform_failure A platform error.

This is an open registry. Map values you do not recognise onto other and keep going; the original is preserved in summary_code_raw when a platform-internal value was normalised to a public one. Read summary_code_raw for traceability, never for branching.

summary_code says what happened. The dimensions say why it came out that way, and they are what you want when a number in a report looks wrong.

reached A live counterpart answered.
not_reached No attempt connected to a person.
voicemail_only Every attempt hit voicemail.
wrong_party Someone answered, but not the subject.
invalid_contact The number is not usable.

engagement - how much conversation actually happened?

Section titled “engagement - how much conversation actually happened?”
none No conversation at all.
hangup_no_interaction Answered and hung up immediately.
identified_then_hangup Identified themselves, then hung up.
declined_conversation Answered and declined to talk.
partial_conversation Some exchange, cut short.
conversation A real conversation took place.

This is the dimension that distinguishes a call where someone picked up and hung up from a ten-minute conversation that concluded nothing. Both used to look identical in reporting; they no longer do.

verified (boolean), method (the verification mode that applied) and attempts.

attempts is present only when a real counter exists. It is not the number of dial attempts - those are two different things, and putting the dial count here would be quietly wrong.

termination - who ended the call, and why?

Section titled “termination - who ended the call, and why?”

actor is subject, agent or system. On orders that never reached a live counterpart it is always system; the block is never invented.

reason is an open registry: completed, subject_hangup, agent_policy, identity_failed, abusive, recording_objection, technical_error, max_duration, not_connected, order_canceled, window_expired, never_attempted.

detail is free text. It is not stable and must never be parsed.

Zero or more typed outcomes. A client must ignore types it does not recognise - new ones are added without a version bump, and a client that throws on an unknown type breaks on a Tuesday for no reason it can see.

Type Carries
payment_promise Amount and due date.
payment_claimed The debtor’s assertion of prior payment.
installment_plan_requested The instalment terms proposed.
dispute_raised The nature of the dispute.
callback_requested The requested time.
contact_update A corrected number or address.
do_not_call_requested An objection to being called again.
escalation_to_human Why it was escalated.
hardship_reported Hardship stated during the call.
information_provided What was asked and answered.
recording_objection An objection to recording.
debtor_deceased Reported death of the debtor.
address_invalid The address is wrong.
insolvency_reported Insolvency proceedings mentioned.
claim_already_settled The claim is said to be settled.

outcomes[].data.scope on do_not_call_requested is deliberately left empty. Whether the person meant “this number” or “me” is not something the runtime records, and guessing it narrow would mean continuing to call someone who objected. The entry blocks both, and it reports what it blocks.

What the agent recorded, and what it did not conclude

Section titled “What the agent recorded, and what it did not conclude”

An instalment plan in outcomes[] is a recorded wish, not an agreement. The agent never concludes one. The binding arrangement is one you make afterwards, in writing, and there is no configuration value that changes this - conclusion_mode is a single-value literal precisely so that nobody can flip it.

The same applies to settlements. negotiation.settlement.min_ratio: 0.6 means the agent may note a 60 per cent offer. It does not mean it may accept one.

Alongside result, every order carries a compliance block.

{
"compliance": {
"ai_disclosure": { "disclosed": true, "at": "2026-08-30T09:14:22+02:00" },
"recording": { "mode": "disabled" },
"statutory_disclosure": null,
"contact_window_policy": "de_uwg7_default"
}
}

ai_disclosure reflects what the platform does - the disclosure is in the opening of every profile and cannot be switched off. It hangs off the answered call rather than standing at a blanket true, so it is a per-call record rather than a claim about the configuration.

delivery.transcript controls how much comes back: none, summary_only, or structured (the default). Whatever you ask for is capped by your tenant’s retention rule - structured never delivers more than the tenant is allowed to retain.

Recording is switched off platform-wide. GET /v1/calls/{call_id}/recording answers 404, and recordings:read grants nothing today. This is current behaviour, not a feature awaiting release.