A call from start to end
Traced at commit ffe4e48 ·
libs/temporal/src/workflows/call-attempt.ts ·
apps/api/src/app/webhooks/{retell,telnyx}.controller.ts ·
libs/temporal/src/activities/call-attempt.ts
Summary
- A workflow owns one call attempt.
- The workflow moves through six states: created, dialing, connected, ended, reconciling, disposed.
- Two providers send messages while the call happens.
- The platform refuses a message with an invalid signature. The platform answers 401.
- The system writes each accepted message once. The platform discards a repeat delivery.
- A message does not change the database directly. The message becomes a signal to the workflow.
- The workflow holds the state. The order of arrival therefore does not matter.
- If the analysis never arrives, a 5-minute timeout disposes the call as
needs_review.
Workflow 1 — the call
The sequence
- The safety gate allows the dial. See The dial gate.
- The workflow starts in the state
created. - The system registers the call with the voice provider and places the call with the carrier.
- The state becomes
dialing. - The carrier sends
call.initiated. - A person answers. The carrier sends
call.answeredandcall.bridged. - The state becomes
connected. - The call ends. The carrier sends
call.hangup. The voice provider sendscall_ended. - The state becomes
ended. - The state becomes
reconciling. The workflow waits for the analysis. - The voice provider sends
call_analyzedwith the transcript. - The system resolves the outcome. See Outcome resolution.
- The state becomes
disposed. The attempt now has one written outcome.
Workflow 2 — one arriving message
The four steps
- The system verifies the signature before it reads the body.
- An invalid signature gives 401. A missing signature also gives 401.
- The system records the refusal with the outcome
invalid_signatureormissing_signature. - The system builds a de-duplication key from the provider, the call id and the event type.
- The system writes the event with
onConflictDoNothingagainst that key. - A second delivery of the same message writes nothing.
- The provider can therefore retry as often as it needs to.
- The system sends the event to the workflow as a signal.
Why this shape. The workflow holds the state, not the message. A duplicate message does no harm, because the database discards the second write. A message that arrives out of order does no harm, because the workflow decides what each one means.
The reconcile timeout
- The default timeout is 5 minutes.
- The timeout starts when the state becomes
reconciling. - If the analysis does not arrive, the workflow disposes the attempt as
needs_review. - A person then reviews the attempt.
- This is the only path that produces an outcome without the provider.
- Every other outcome comes from messages that arrived.
- A call is never left open.
Outcome resolution — what the platform does with the transcript once the call has ended.