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

# The nextAction Contract

> The object on every Agent Pay result that tells you what has to happen next, and who has to do it.

**You don't need this page to ship.** [Embedded checkout](/agent-pay/embed) reads `nextAction` for you, and so
does the [Approvals SDK](/agent-pay/approvals). Read on if you're rendering payment UI yourself, relaying actions
through a channel Atoa doesn't know about, or want to see what the embed switches on.

Every Agent Pay result carries one `nextAction`: the single thing that must happen next. It holds the ids,
amounts and links a renderer needs, so you never pick fields out of a raw response. With no UI, poll
`nextAction.resolve` until the status is terminal. In a chat, post `nextAction.fallback.text`.

## The shape

| Field          | Type                              | Meaning                                                                                                                        |
| -------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `v`            | `1`                               | Envelope version.                                                                                                              |
| `type`         | string                            | The action kind — the [catalogue](#the-catalogue) below. New types can appear: switch on it and fall back on anything unknown. |
| `state`        | string?                           | Where the flow is — the underlying payment/contract status when there is one.                                                  |
| `for`          | `'customer' \| 'owner' \| 'none'` | **Who must act.** `'none'` tells an agent NOT to prompt a human.                                                               |
| `expiresAt`    | ISO datetime?                     | When the action lapses.                                                                                                        |
| `mustEscalate` | boolean                           | Reserved. Always `false` today — no action currently needs a top-level window.                                                 |
| `data`         | object                            | Everything a surface needs, by type — **additive-only**: ignore fields you don't know.                                         |
| `fallback`     | `{ text, url }`                   | **Present on every action.** One sentence and a link — the plain-text path when you render nothing. Never carries a secret.    |
| `resolve`      | `{ poll, id, until }`?            | How to learn it finished: poll `'payment' \| 'contract' \| 'approval'` with `id` until a status in `until`.                    |

Read approval fields from `data`: `data.approvalId`, `data.approvalUrl`, `data.clientSecret`. The same three are
also mirrored at the top level of `nextAction` for backwards compatibility.

## The catalogue \[#the-catalogue]

Four types. That's the whole set an Agent Pay call can return today.

| `type`               | Who acts          | What it asks for                                                                                                                                                                                        |
| -------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PAY`                | customer          | Pay an open pay-link — `data.paymentRequestId`, `amount`, `hostedUrl`.                                                                                                                                  |
| `APPROVAL`           | customer or owner | The SCA [approval gate](/agent-pay/reference#approval-gate) (SCA: the approver's one-time code or passkey check) — `data.approvalId`, `approvalUrl`, `clientSecret`.                                    |
| `AUTHORIZE_CONTRACT` | customer or owner | Authorise a contract — `data.kind` says which page: `'collect'` (customer links a method + approves) or `'cvrp'` (a commercial Variable Recurring Payment — the account holder consents at their bank). |
| `NONE`               | none              | Terminal. State the outcome, ask for nothing.                                                                                                                                                           |

Choosing a card, entering card details, verifying a contact, enrolling a passkey — those are **steps inside** a
`PAY`, `APPROVAL` or `AUTHORIZE_CONTRACT` flow, handled on Atoa's pages. They never arrive as a `nextAction` you
have to render.

## Handling a type you don't know

**When you get a `type` you don't recognise, render `fallback.text` and `fallback.url`.**

`type` is a plain string, not an enum, so Atoa can add action types without an SDK release. Every action type has
a usable `fallback`. The embed does this for you.

`fallback.text` never contains a `clientSecret`, so it's safe to post to a chat or an email.

## Amounts are pre-formatted

`data.amount` is `{ value, currency, display }` — `value` is a decimal **string**, exactly as sent on the wire;
`display` is pre-formatted (`"£45.00"`). Print `display`; never format money yourself.

```json theme={null}
{
  "v": 1,
  "type": "PAY",
  "state": "PENDING",
  "for": "customer",
  "mustEscalate": false,
  "data": {
    "paymentRequestId": "prq_a81f…",
    "amount": { "value": "45.00", "currency": "GBP", "display": "£45.00" },
    "orderId": "booking-8812",
    "hostedUrl": "https://pay.atoa.me/prq_a81f…"
  },
  "fallback": {
    "text": "Pay £45.00 securely from your bank: https://pay.atoa.me/prq_a81f…",
    "url": "https://pay.atoa.me/prq_a81f…"
  },
  "resolve": { "poll": "payment", "id": "prq_a81f…", "until": ["COMPLETED", "FAILED", "CANCELLED", "EXPIRED"] },
  "source": "sdk"
}
```
