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

# Resolution Flow

> The user journey — BotShield Q push to biometric Confirm to Proof of Resolution — and the full Q card lifecycle.

# Resolution Flow

This page traces a proposed action from the moment an agent calls [`inquire`](/queue/agent-integration#proposing-an-action) to the moment the agent receives a signed verdict. It covers what the **user** experiences and the states a **Q card** moves through.

## The user journey

<Steps>
  <Step title="A BotShield Q push arrives">
    When the agent proposes an action, BotShield sends the user a **BotShield Q push notification** to the BotShield app. The notification is intentionally thin: it carries the `request_id`, the agent's display name, and the action summary. It does **not** carry the card body.
  </Step>

  <Step title="The user opens the Q card">
    In the app, the action appears as a **Q card** describing what the agent wants to do — the summary title, an optional detail row (e.g. `TOTAL · $48.00`), the requesting agent, the Trusted Account the action would use, and the time remaining before it expires. The header reads **"BotShield Q"** whenever cards are waiting.
  </Step>

  <Step title="The user stages a decision">
    The user taps **Confirm** or **Deny**. A user can stage decisions across several pending cards and resolve them together.
  </Step>

  <Step title="Biometric ceremony">
    The user completes a single **Face ID / Touch ID** ceremony (hardware-backed, via the Secure Enclave). One ceremony can resolve **N** staged cards at once.
  </Step>

  <Step title="Proof of Resolution issued">
    On a successful ceremony, BotShield signs one [Proof of Resolution](/queue/proof-of-resolution) per card and delivers it back to each card's agent. The cards move to their terminal state.
  </Step>
</Steps>

<Info>
  **One ceremony, N proofs.** When a user confirms several cards in one Face ID touch, every resulting Proof of Resolution shares the same `ceremony_id` — but each is independently verifiable by its own agent, and no agent sees another agent's proof.
</Info>

## Q card states

A Q card has a single, terminal lifecycle. Once it leaves `queued`, it never returns.

```mermaid theme={null}
stateDiagram-v2
    [*] --> queued: agent inquire
    queued --> approved: Confirm + biometric
    queued --> denied: Deny + biometric
    queued --> cancelled: agent cancel
    queued --> expired: TTL lapses
    approved --> [*]
    denied --> [*]
    cancelled --> [*]
    expired --> [*]
```

| State       | Meaning                                                                     | Proof of Resolution?    |
| ----------- | --------------------------------------------------------------------------- | ----------------------- |
| `queued`    | The card is live on the user's device, awaiting a decision, until `ttl_at`. | —                       |
| `approved`  | The user confirmed with a biometric.                                        | Yes — verdict `approve` |
| `denied`    | The user explicitly declined with a biometric.                              | Yes — verdict `denied`  |
| `cancelled` | The agent withdrew the proposal before the user acted.                      | No                      |
| `expired`   | The TTL lapsed with no response.                                            | No                      |

<Warning>
  **Absence is the signal.** `cancelled` and `expired` produce **no** Proof of Resolution. A timed-out or withdrawn action is simply *not authorized* — there is no negative token to deliver. Only an explicit `denied` carries a signed verdict.
</Warning>

## How the agent learns the outcome

The agent receives the result two ways — use whichever fits:

* **Poll.** Call [`agentlink/check-status`](/queue/api-reference#check-status) with the same `request_id`. Once the card resolves, the response carries the `resolution_jwt` and `verdict`.
* **Webhook.** BotShield fires a [Svix-signed webhook](/queue/proof-of-resolution#webhook-events) — `q.resolution.confirmed`, `q.resolution.denied`, or `q.resolution.expired` — to your registered endpoint. This is push, not poll, and is delivered with retries. (These events are defined but [not yet firing for agent-proposed cards in the current build](/queue/proof-of-resolution#webhook-events) — poll for now.)

A common hybrid: the agent polls for a short window for a snappy in-conversation result, and your backend relies on the webhook for the durable record in case the agent's task ends before the user responds.

## Cancellation and expiry

* **Cancel** is agent-initiated. Call [`agentlink/cancel`](/queue/api-reference#cancel) while the card is still `queued` to withdraw it. It is a no-op (idempotent) if the card has already resolved.
* **Expiry** is automatic. A periodic internal sweep marks every `queued` card past its `ttl_at` as `expired` and fires `q.resolution.expired`. The default TTL is 10 minutes; agents may request `[60, 86400]` seconds.

## Failed biometric

If the biometric ceremony fails (wrong face, cancelled prompt), **no** Proof of Resolution is produced and the staged cards remain `queued` — the user can simply retry. A failed ceremony is architecturally identical to a timeout: an absence of attestation, never a `denied`.

## Next steps

<CardGroup cols={2}>
  <Card title="Proof of Resolution" icon="badge-check" href="/queue/proof-of-resolution">
    The signed artifact: claims, JWKS verification, and webhook payloads.
  </Card>

  <Card title="Q API Reference" icon="code" href="/queue/api-reference">
    Every operation with request and response shapes.
  </Card>
</CardGroup>
