diff --git a/content/guides/calls.mdx b/content/guides/calls.mdx index 2a48e85..ff0b023 100644 --- a/content/guides/calls.mdx +++ b/content/guides/calls.mdx @@ -387,6 +387,11 @@ Use a stable workflow key, not a random UUID generated at each retry. Use `waitForResult` or `wait_for_result` for simple server-side polling. Use events when you need a developer-facing trace of the call lifecycle. +Before mapping a failed call to no answer or decline, read +[Accepted call execution outcomes](/errors#accepted-call-execution-outcomes). +Calls API `failure_code` values are not a published enum, and Goal Run error +codes do not define the Calls API contract. + When the terminal `structured_result` is `null`, CALL-E did not produce a schema-valid whole-task result from the available evidence. Recipient-level structured results use the same rule: invalid or unsupported values are returned as `null`. The task-level `task_completed`, `completion_confidence`, and `evidence` fields come from the post-call summary and are available independently of your custom result schema. Each recipient attempt can include `transcript_turns`, an ordered list of structured transcript turns for that dial attempt. Each turn has `offset_seconds`, `speaker`, and `text`; `speaker` is `bot`, `user`, or `unknown`. The array is empty when no transcript is available. diff --git a/content/guides/errors.mdx b/content/guides/errors.mdx index 44a7f15..186fefc 100644 --- a/content/guides/errors.mdx +++ b/content/guides/errors.mdx @@ -46,6 +46,30 @@ SDK methods raise typed SDK errors while preserving the stable API error code an - `internal_error` - `not_found` +## Accepted call execution outcomes + +The stable `APIError.code` values above describe an HTTP request failure. They +are separate from the outcome of a call task or Goal Run that was accepted and +later reached a terminal state. + +| Surface | Stable contract | +| --- | --- | +| Developer API request | `APIError.code` uses the stable values listed above. | +| Calls API call task | Lifecycle `status` is stable. `failure_code` is a nullable string without a published enum; `failure_message` is nullable human-readable context. | +| Goal Runs API | `GoalRunError.code` is a separate enum that includes `no_answer` and `declined`. | + +For Calls API resources, treat `failure_code` and `failure_message` as +diagnostic context. Preserve the raw values for support, but do not branch +retry, reporting, or analytics logic on a particular string. + +The Goal Run codes `no_answer` and `declined` do not define Calls API +`failure_code` values. The Calls API currently does not guarantee a distinct +no-answer or callee-decline value at the call-task, recipient, or attempt +level. If the documented Calls fields do not establish that distinction, keep +the business outcome unresolved. Do not infer that a recipient declined from +a generic `failed` state or an undocumented failure message, and do not +automatically retry based only on an undocumented failure string. + ## Recovery guidance `unauthorized` means the API key is missing or invalid. Check the `Authorization: Bearer` header. diff --git a/tests/docs-site.spec.ts b/tests/docs-site.spec.ts index cc370df..368b5d0 100644 --- a/tests/docs-site.spec.ts +++ b/tests/docs-site.spec.ts @@ -439,6 +439,29 @@ test("connects the Calls guide to HTTP and related references", async ({ await expect( callsBody.locator('p a[href="/webhooks"]'), ).toBeVisible(); + + const outcomeGuidance = callsBody.getByRole("link", { + name: "Accepted call execution outcomes", + }); + await expect(outcomeGuidance).toHaveAttribute( + "href", + "/errors#accepted-call-execution-outcomes", + ); + await outcomeGuidance.click(); + + await expect(page).toHaveURL(/\/errors#accepted-call-execution-outcomes$/); + await expect( + page.getByRole("heading", { name: "Accepted call execution outcomes" }), + ).toBeVisible(); + const callsOutcomeWarning = page.locator("main p").filter({ + hasText: "do not define Calls API", + }); + await expect(callsOutcomeWarning).toContainText( + "keep the business outcome unresolved", + ); + await expect( + callsOutcomeWarning.locator("code").filter({ hasText: "failure_code" }), + ).toBeVisible(); }); test("documents the published Goal Run flow on a clean route", async ({