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

# Limits and errors

> Lifetimes, rate-limit keying, every error code.

```ts theme={null}
const result = await payman.forUser(userId).run(text);

if (result.kind === "error") {
  show(result.guidance);                            // written for humans
  if (result.retryable) retryLater(result.retryAfterMs ?? 1000);
}
```

Every wire failure comes back as the `error` result kind; `run()` never throws for them. On the blocking route the SDK retries a retryable failure once before resolving; streamed turns resolve without a retry. Schedule any second attempt for later and honour `retryAfterMs` when it is set.

## Lifetimes

| What                   | Lifetime                                                 | On expiry                                                        |
| ---------------------- | -------------------------------------------------------- | ---------------------------------------------------------------- |
| Connection (the grant) | 90 days                                                  | `run()` returns `needs_connection`; offer the button again       |
| App registration       | 90 days                                                  | Renew it from the developer console; existing connections resume |
| Authorization code     | 60 seconds, single use                                   | It burns on a failed exchange too; start the flow again          |
| Approval               | About 15 minutes, stamped on the approval as `expiresAt` | The state becomes `expired`; run the turn again                  |

`status()` reports `health: "expiring_soon"` from 14 days out on either 90-day clock.

## Rate limits

The budgets are deploy configuration, so no figures here. The keying is the contract:

| Traffic                                                                     | Keyed on  |
| --------------------------------------------------------------------------- | --------- |
| Turns and their follow-ups (interact, stream, user actions, approval polls) | The grant |
| Credential minting (register, rotate, renew)                                | The user  |
| The token exchange and the app self-read                                    | The app   |
| The public consent read, and everything unauthenticated                     | IP        |

Per grant is the one to pace: each customer budgets separately, so the traffic that hits it is yours, and one customer can never starve another. A 429 surfaces as `rate_limited`.

## Error codes

`result.code` is a closed set.

| Code                    | Retryable | Meaning                                                                                        |
| ----------------------- | --------- | ---------------------------------------------------------------------------------------------- |
| `invalid_request`       | No        | Malformed call. Your bug.                                                                      |
| `needs_connection`      | No        | Never actually surfaces as an error: a 401 becomes the `needs_connection` result kind instead. |
| `connect_grant_race`    | No        | The customer reconnected in another tab, replacing this grant. Offer consent again.            |
| `deployment_paused`     | No        | Paused from the customer's Payman console. Only they can resume it.                            |
| `deployment_incomplete` | No        | The customer's Payman setup is unfinished. Not fixable from your app.                          |
| `insufficient_scope`    | No        | The grant does not cover the operation.                                                        |
| `agent_failed`          | No        | The customer's own agent answered, and the answer was that it could not do it.                 |
| `agent_timeout`         | Yes       | The customer's own agent took too long.                                                        |
| `agent_unreachable`     | Yes       | The customer's own agent could not be reached.                                                 |
| `rate_limited`          | Yes       | Too many requests. `retryAfterMs` says how long to wait.                                       |
| `server_error`          | Yes       | Payman had a problem.                                                                          |
| `stream_error`          | Yes       | The stream ended without a result. The turn failed; nothing was delivered.                     |
| `transport_error`       | Yes       | Could not reach Payman at all. Check connectivity and `PAYMAN_BASE_URL`.                       |

`deployment_paused` and `deployment_incomplete` never succeed on retry. Alert yourself rather than asking the customer to fix them mid-conversation.

## The served contract

HTTP statuses and wire result names live in [the HTTP API](/reference/http-api). The spec itself is served on the API origin and parity-tested against the router on every build, so a route it does not describe does not exist:

```bash theme={null}
curl -s https://api.paygent.payman.ai/openapi/paygent-cloud-api.yaml
```

The tool definition is served the same way, versioned by date:

```bash theme={null}
curl -s https://api.paygent.payman.ai/connect/tool-definition | jq .version
```
