> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget and ambient-agent action refusals

> Decode every refusal the embedded widget and its ambient agent can return — AGENT_ACTION_DENIED, AGENT_ACTION_RATE_LIMITED, AGENT_ACTION_CAP_REACHED, the embed-origin codes, WIDGET_DISABLED, WIDGET_BUNDLE_UNAVAILABLE, NOT_IN_QUEUE, VOICE_AGENT_UNAVAILABLE, and the transcript-email pair — and apply the one fix each.

# Widget and ambient-agent action refusals

The widget's action endpoints — callback scheduling, the transcript
email, and queue-position reads — answer with a structured `code` when
they refuse a request. Most of these codes are a configuration or a
pace signal you own, not an outage. This runbook decodes each one and
names the one fix that clears it.

A browser-resident (ambient) agent that drives the widget on a
visitor's behalf signs its requests, and those signed requests pass
through extra gates a plain human visitor never touches. If your
visitors are humans only, the codes you will see are the embed-origin,
widget-state, queue, and transcript ones below; the three
`AGENT_ACTION_*` codes only ever answer an agent-attributed request.

## One ledger, three lanes

Every visitor session keeps one action ledger, and three lanes read
from it before an agent-attributed callback is allowed through
([Widget flow model](https://docs.orbit.devotel.io/concepts/widget-flow-model.md) has the full
mechanics):

1. **Action rate lane** — a sliding window scoped to the session:
   5 callbacks/hour and 30 messages/hour by default. A request that
   would breach the window is refused with `Retry-After` seconds and
   charges nothing.
2. **Per-session caps** — cumulative ceilings of 50 actions or 100
   preview-cost units per session, so a long-lived session cannot grind
   under the hourly lane. A refusal here names the only way out: a new
   session.
3. **Compliance (quiet hours)** — an agent-scheduled callback is a
   future outbound voice leg, so it runs through **your** tenant's
   quiet-hours window for the voice channel. The gate is default-OPEN:
   it only refuses when you have opted the voice channel into quiet
   hours and the recipient's local time is outside your window, and it
   tells you `next_allowed_at` when it does.

In front of all three sits the trust gate: the widget's agent
capability and trust policy decide whether a given agent may act on
this widget at all. Every agent-attributed action — allowed or refused
— is logged, so you can reconstruct what a browser agent did.

A scheduled callback that clears these gates is placed exactly like
your queue callbacks — your routing, your dialing windows. Nothing on
this page adds or bypasses an outbound path.

## Code by code: cause and fix

| Code | Status | Cause | Fix |
| - | - | - | - |
| `AGENT_ACTION_DENIED` | 403 | The agent that signed the request is not permitted to act on this widget — the agent capability switch or the trust policy in the widget's configuration refuses it. This is a per-widget decision about this agent, not a platform-wide ban on your workspace or the agent's vendor. | Allow the agent (or its directory) and the capability it attempted under **Settings → Native Chat**. The next action request picks the change up. |
| `AGENT_ACTION_RATE_LIMITED` | 429 | The session's sliding-window callback lane is full (default 5 callbacks/hour). The response carries a `Retry-After` header. | Wait out the `Retry-After` seconds before the next attempt, and space the agent's actions. Do not retry in a loop — an immediate repeat fails identically and keeps the session inside the window. |
| `AGENT_ACTION_CAP_REACHED` | 429 | The session spent its cumulative cap (default 50 actions / 100 preview-cost units). The message says it plainly: start a new session to continue. | Start a new visitor session. The cap is per-session by design; there is no switch to raise it mid-session, and a retry inside the same session never clears it. |
| `QUIET_HOURS_BLOCKED` | 422 | The recipient's local time is outside your tenant's voice-channel calling window. This only fires when you opted the voice channel into quiet hours — the default posture is open. | Wait for `details.next_allowed_at`, or widen the window in your compliance settings. The refusal carries your own configured reason. |
| `ORIGIN_HEADER_REQUIRED` | 400 | The page that loaded the widget sent no `Origin` header, so the embed gate cannot check it. | Load the widget from a normal browser page load (which always sends `Origin`); check proxies or unusual iframe setups that strip the header. |
| `ORIGIN_NOT_CONFIGURED` | 403 | The widget's allowed-origins list is empty. The embed gate is closed by default until you name the sites that may run the widget. | Add your site's origin under the widget's allowed origins in **Settings → Native Chat**. |
| `ORIGIN_NOT_ALLOWED` | 403 | The page's origin does not match any entry in the widget's allowed origins. | Add the exact origin — scheme, host, and port. `https://shop.example.com` does not cover `https://www.example.com` or a localhost development port; add each one you serve from. |
| `WIDGET_DISABLED` | 403 | The widget is disabled for this workspace. | Re-enable it under **Settings → Native Chat**; the embed starts answering again immediately. |
| `WIDGET_BUNDLE_UNAVAILABLE` | 503 | The embed script could not fetch the compiled widget bundle from this deployment. | Nothing on your side is misconfigured — keep the `<script>` tag in place; it recovers with the next deploy. If it persists for more than a few minutes, contact support with the snippet URL. |
| `NOT_IN_QUEUE` | 409 | The action assumed the visitor's conversation was waiting in a queue, and it is not — the conversation was answered, left, or never had a queue attached. | Re-read the conversation's queue state before requesting the action; a repeat fails identically until the state changes. |
| `VOICE_AGENT_UNAVAILABLE` | 503 | The voice agent the widget needs for the call could not be attached — no agent is bound, the bound agent is paused, or it is momentarily unavailable. | Retry once with a short backoff; if it persists, check that the widget has an active voice agent attached. |
| `TRANSCRIPT_EMPTY` | 422 | A transcript email was requested for a session with no messages — there is nothing to render. | The visitor gets a transcript once the session has at least one exchanged message. |
| `TRANSCRIPT_EMAIL_FAILED` | 502 | The transcript email send failed at the email leg. | Have the visitor request the transcript again — each request sends fresh. If repeats fail, escalate with `meta.request_id`. |

## Retry classes

The same three classes the
[Error Code Reference](https://docs.orbit.devotel.io/reference/error-codes.md#from-a-code-to-a-runbook)
routes by apply here:

| Class | Codes on this page | Retry posture |
| - | - | - |
| Deterministic | `AGENT_ACTION_DENIED`, `ORIGIN_HEADER_REQUIRED`, `ORIGIN_NOT_CONFIGURED`, `ORIGIN_NOT_ALLOWED`, `WIDGET_DISABLED`, `NOT_IN_QUEUE`, `TRANSCRIPT_EMPTY`, `QUIET_HOURS_BLOCKED` | Never retry blind — the request fails identically until the configuration, the origin, or the conversation state changes. |
| Transient | `WIDGET_BUNDLE_UNAVAILABLE`, `VOICE_AGENT_UNAVAILABLE`, `TRANSCRIPT_EMAIL_FAILED` | Retriable with a short backoff; if the 503/502 persists, the escalation column in the table above names what to send. |
| Conditional | `AGENT_ACTION_RATE_LIMITED`, `AGENT_ACTION_CAP_REACHED` | Retry only when the named condition holds: after the `Retry-After` window elapses, or in a new session. A loop inside the same window or session only extends it. |

## Fixes that never help

* Retrying `AGENT_ACTION_RATE_LIMITED` without waiting out
  `Retry-After` — the sliding window counts the retries too.
* Retrying `AGENT_ACTION_CAP_REACHED` in the same session — the cap is
  cumulative by design.
* Re-sending an origin-failed embed from the same page — the origin is
  a property of the page that serves the widget, not of the request
  your script builds.
* Reading `AGENT_ACTION_DENIED` as a billing or account suspension —
  it is always the widget's own agent capability and trust
  configuration.

## Related surfaces

* [Widget flow model](https://docs.orbit.devotel.io/concepts/widget-flow-model.md) — the lane
  mechanics, the trust policy, and the transcript renderer behind this
  page.
* [Agent runtime errors](https://docs.orbit.devotel.io/troubleshooting/agent-errors.md) — the six
  runtime codes (`AGENT_ERROR` … `LLM_PROVIDER_ERROR`) when the AI
  agent itself fails, as opposed to being refused by a widget gate.
* [Agent outbound-call and voice-clone guard
  codes](https://docs.orbit.devotel.io/troubleshooting/agent-outbound-guards.md) — the pre-origination
  guard family on the voice side.
* [Web widget API reference](https://docs.orbit.devotel.io/api-reference/web-widget.md) — the embed
  surface, including re-enabling a disabled widget.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.