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

# Payment Workflow

> The request → poll → learn loop for agent payments

Agent payments follow one loop: **attempt or request a payment, poll until terminal, and learn from denials.**

<Steps>
  <Step title="Request the payment">
    Call `request_wallet_payment` (or `submit_approval_request` to explicitly ask a human first):

    ```json theme={null}
    {
      "purpose": "Monthly data feed subscription for market analysis",
      "amountCents": 4900,
      "recipient": "0x7a3f...8c21",
      "caip2": "eip155:8453",
      "idempotencyKey": "datafeed-sub-2026-07"
    }
    ```

    The response is a verdict, and every **non-terminal** verdict includes a `requestId` to poll:

    | Verdict               | Meaning                                                                                                            |
    | --------------------- | ------------------------------------------------------------------------------------------------------------------ |
    | `submitted`           | Within policy — accepted and settling on-chain. **Still poll it.**                                                 |
    | `funding_in_progress` | Within policy — the platform is topping up the agent wallet first, then executing. **Still poll it.**              |
    | `pending_approval`    | Above your threshold (or flagged) — waiting on a human. Poll it.                                                   |
    | `denied`              | Blocked by policy — read the denial reason; do not retry unchanged.                                                |
    | `failed`              | Terminal — couldn't execute (e.g. insufficient treasury funds, provider failure). Includes a denial code + reason. |

    <Warning>
      `submitted` is acceptance, not settlement. Treat every non-terminal verdict the same way: keep
      polling until terminal.
    </Warning>
  </Step>

  <Step title="Poll until terminal">
    Call `check_approval_status`, passing the `requestId` from the response as the `request_id` parameter (the response field is camelCase; the read tool's parameter is snake\_case). Honor `retry_after_seconds` in each response — it backs off from 30s toward 5 minutes the longer a human takes to decide.

    | Status     | Meaning                                                              | Keep polling?                   |
    | ---------- | -------------------------------------------------------------------- | ------------------------------- |
    | `pending`  | Awaiting human decision                                              | Yes                             |
    | `approved` | Wallet payments: **transfer in flight** — Reinx executes on approval | **Yes**                         |
    | `used`     | Settled successfully                                                 | No — done                       |
    | `failed`   | Execution failed (includes `failure_code` + `failure_reason`)        | No                              |
    | `denied`   | Human denied it                                                      | No — read the feedback          |
    | `expired`  | Human didn't decide within the approval window                       | No — re-request if still needed |

    <Warning>
      For wallet payments, `approved` is **not** success — the transfer is still executing on-chain.
      Only `used` means the money moved.
    </Warning>
  </Step>

  <Step title="Learn from denials">
    On a denial, call `get_denial_feedback` — the human's feedback text tells the agent what to change before retrying (or whether to stop asking).
  </Step>
</Steps>

## Idempotency

Pass a stable `idempotencyKey` (8–200 chars) per **logical payment**:

* Retrying with the **same key and the identical request** after a timeout or upstream error is safe — it deduplicates and will never double-spend.
* Reusing a key with **any changed field** — amount, recipient, `caip2`, `asset`, `purpose`, or `justification` — is rejected with a `409` conflict. Resend the complete request unchanged when retrying.

## Parameter casing

* **Write tools** (`request_wallet_payment`, `submit_approval_request`) use camelCase canonically (`amountCents`, `idempotencyKey`) but also accept snake\_case aliases (`amount_cents`, `idempotency_key`). Supplying both with different values is rejected.
* **Read tools** use snake\_case (`request_id`, `lookback_days`, `mcc_code`).

## Networks and assets

* `caip2` selects the network. Supported in production: Base (`eip155:8453`), Polygon (`eip155:137`), Arbitrum (`eip155:42161`), Optimism (`eip155:10`), and Solana (`solana:mainnet`).
* `asset` defaults to **USDC**. Gas is sponsored — agents never hold ETH or SOL.
* Recipient addresses are validated per chain family (EIP-55 checksum for EVM, base58 for Solana).

## The purpose field

Every tool call requires `purpose` (3–500 characters) explaining *why* the agent is acting. It's recorded in the immutable audit log, shown to humans on approval requests, and feeds the agent's behavioral scoring. You may reuse one stable purpose string across the polls of a single payment loop.

## Errors and limits

* Invalid or revoked API key → `401 UNAUTHORIZED`.
* Paused agent → `403 AGENT_PAUSED` (pausing keeps the key). Archiving revokes the key, so an archived agent gets `401`.
* Rate limits: general tool calls are limited per your plan tier; the payment tools have tighter limits (10/min per key, 30/min per org). A `429` includes a `retry-after` header.
