# Intents

An **intent** is a request, in natural language, for something to be bought or
booked. OpenIntents turns it into a completed transaction or a clear failure.

## Writing a good intent

Be as specific as a person would need to be. The agent asks for nothing mid-run
unless it needs a [payment link](/docs/wallets#payment-links), so include what matters:

- **What:** _"large oat flat white"_, _"UberX, not Comfort"_
- **Where or from whom:** a merchant, a location, or _"cheapest option"_
- **When:** _"pickup 8:45"_, _"leaving at 7am"_, _"arrive by Friday"_
- **Constraints:** _"aisle seat"_, _"under $400"_, _"refundable only"_

Anything structured (addresses, names, loyalty numbers) is better passed in
`context` than in the sentence.

## The intent object

```json
{
  "id": "int_7f3a2c",
  "object": "intent",
  "status": "running",
  "intent": "one-way flight JFK to Lisbon on the 14th, aisle seat, under $400",
  "max_amount": 40000,
  "currency": "usd",
  "context": { "traveler": { "name": "Ada Lovelace", "dob": "1990-12-10" } },
  "metadata": { "trip_id": "tr_881" },
  "result": null,
  "error": null,
  "test": false,
  "created_at": "2026-10-01T08:30:00Z",
  "completed_at": null
}
```

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Unique ID, prefixed `int_`. |
| `status` | string | One of the statuses below. |
| `intent` | string | The natural-language request, as sent. |
| `max_amount` | integer | Spending cap in cents, including tax and delivery. Optional. |
| `context` | object | Structured details the agent may use (addresses, names, preferences). |
| `metadata` | object | Your own key/value pairs, returned untouched. |
| `payment` | object | Set when `requires_payment`: `payment_url`, total, fee and why a link is needed. |
| `result` | object | Set when `completed`: merchant, items, total, fee, confirmation, receipt URL. |
| `error` | object | Set when `failed`: `code` and a human-readable `message`. |
| `test` | boolean | `true` for intents created with a test key. |

## Lifecycle

```text
queued ──► running ──► (paid from balance) ──────────► completed
              │                                           ▲
              ├──► requires_payment ──► (link paid) ──────┘
              │           │
              │           └──► cancelled (link expired or cancelled)
              └──► failed
```

| Status | Meaning |
| --- | --- |
| `queued` | Accepted, waiting for a browser. Usually under a second. |
| `running` | The API is doing the agentic work in a real browser. |
| `requires_payment` | At checkout, and the [balance](/docs/wallets) can't or shouldn't pay. `payment.payment_url` is set; the intent completes once it's paid. |
| `completed` | Paid (from the balance or a link) and confirmed. `result` is set. |
| `failed` | Could not be completed (out of stock, over `max_amount`, merchant error). Free. |
| `cancelled` | Cancelled by you before payment. Free. |

`completed`, `failed` and `cancelled` are final. Every transition emits a
[webhook](/docs/webhooks) event.
