---
name: "hightop-agent-api"
description: "Operate a Hightop wallet programmatically over the Hightop Agent API v1: read balances and activity, send payments, convert assets, earn, borrow/repay, and pay x402 or MPP invoices with real funds. Use when an agent holds Hightop agent credentials (header key or OAuth bearer) and needs to read account state or move money."
---

<!-- Generated by scripts/generateAgentSkill.ts from the Agent API v1 contract. Do not edit by hand. -->

# Hightop Agent API skill

This skill teaches an AI agent how to operate a Hightop wallet through the **Agent API v1** (contract `1.9.0`, base path `/v1/agent`). Production write endpoints move **real funds** on Base; treat every mutation as a real money movement.

Read the "Choose a channel", "Authenticate", and "Golden rules" sections once, then jump to the recipe you need. The "Reference" section at the bottom is the authoritative, machine-generated list of endpoints, scopes, error codes, and limits — consult it instead of guessing.

## When to use this

Use this skill when you hold Hightop agent credentials and need to read account state or move money: check balances, send a payment, convert assets, deposit/withdraw from earn, borrow or repay, or pay an x402 or MPP invoice. If you only need the raw machine contract, fetch the public `GET /v1/agent/openapi.json`; authenticated Agent API callers can also fetch `GET /v1/agent/capabilities.json`.

## Choose a channel

The same capability surface is reachable several ways. Pick one:

- **MCP** (`/mcp`) — use if you are an MCP host (Claude Desktop, ChatGPT, Cursor). Every agent-callable contract route (the capabilities catalog) is exposed as an MCP tool over JSON-RPC 2.0, with the same auth, scopes, idempotency, and errors. Best for conversational/tool-calling agents.
- **TypeScript SDK** (`@hightop/sdk`) — use if you are writing TypeScript. The typed `HightopAgentClient` handles auth, idempotency, timeouts, and operation polling; non-2xx responses throw `HightopAgentSDKError` exposing `code` and the normalized `agentError` directly.
- **CLI** (`@hightop/cli`) — use for scripting or one-shot calls. Install the package, set `HIGHTOP_BASE_URL` plus either `HIGHTOP_AGENT_ID`/`HIGHTOP_API_KEY` or `HIGHTOP_BEARER_TOKEN`, then run `hightop` commands derived from the endpoint catalog (e.g. `hightop self`; `hightop --help` lists them).
- **Raw HTTPS** — use for any other language or a thin integration. Call `/v1/agent/*` directly; this skill's recipes show the raw requests.

The recipes below are written as raw HTTPS so they translate to any channel.

## Authenticate

Two credential types resolve to the same agent identity. Send exactly one.

**Header-key (internal / legacy):**

```txt
x-agent-id: <agent uuid>
x-api-key: <agent api key>
```

**OAuth 2.1 Bearer (third-party callers):**

```txt
Authorization: Bearer <jwt>
```

Bearer tokens come from the Hightop authorization server via Authorization Code + PKCE (S256) with an RFC 8707 `resource` indicator. Tokens are audience-bound: a token minted for `/v1/agent` cannot be used at `/mcp` and vice versa. Discover the AS at `GET /.well-known/oauth-protected-resource/v1/agent`.

OAuth tokens carry scopes; a route missing its required scope returns `403 insufficient_scope` with a `WWW-Authenticate` header naming the scope. The required scope per route is in the Reference endpoint list, and the full scope catalog is under "OAuth scopes" in the Reference section below.

## Money-movement rails: pick the right one

- **Recurring payment recipient.** Use for repeat payments to an owner-approved vendor or service. The owner creates the recipient and sets its caps/cadence in the app. Once active, the agent pays it through `POST /v1/agent/payments`; there is no agent-side time-lock on each payment.
- **One-off payment.** Use for a single ad hoc payout to a fresh address with `POST /v1/agent/one-off-payments`. Owner-configured review delay, expiry, and claim/payment rules apply. In Agent API v1 the agent supplies only `to`, `asset`, and `amount`/`amount_usd`; custom `unlock_delay_seconds` or `expires_in_seconds` values are rejected with `validation_failed`.
- **Withdrawal.** Use only to move funds out of Hightop to an owner-trusted bank or crypto destination through `POST /v1/agent/withdrawals/to-bank` or `POST /v1/agent/withdrawals/to-crypto`. Trusted destinations are owner-created with an activation delay often measured in days; an agent can confirm, cancel, or remove existing trusted-destination entries when authorized, but cannot initiate adding a new destination.

To pay a service, use `POST /v1/agent/payments` for approved recipients or `POST /v1/agent/one-off-payments` for a one-time fresh-address payout. Do not withdraw first.

## Rules layer: why an action is blocked

The owner configures the agent's lane: permissions, allowed assets and venues, per-transaction/per-period/lifetime USD caps, transaction-count caps, cooldowns, max slippage, and activation/expiry windows. Rules are enforced onchain using the effective settings returned by `GET /v1/agent/self/limits`: most caps use the tightest or strictest applicable value, with documented exceptions. The agent cannot widen its own permissions, add new recipients, or relax limits.

Read your own configured caps, granted operations, and current-period usage with `GET /v1/agent/self/limits` (per-transaction / per-period / lifetime USD caps, transaction-count cap, cooldown, max slippage, plus how much you have already spent and how many transactions you have made this period). It also returns `permissions` — the operation types YOU are actually granted, split into `operation_types` and `cannot`. Use it to size a payment before submitting (instead of discovering a cap through a `limit_exceeded` rejection) and to check whether an operation is even permitted before attempting it. These are your real grants, unlike `GET /v1/agent/self`, which lists the global capability catalog. A `null` cap means no limit of that kind is configured.

If a request returns `limit_exceeded`, `policy_rejected`, `permission_not_granted`, `recipient_not_allowed`, or `asset_not_allowed`, surface the block to the owner and do not retry unchanged. For the full owner-facing rule model, see [Permissions and Limits](https://www.hightop.com/docs/control-agents/permissions-and-limits), [Recurring Payments](https://www.hightop.com/docs/control-agents/recurring-payments), [One-Off Payments](https://www.hightop.com/docs/control-agents/one-off-payments), and [Trusted Transfers](https://www.hightop.com/docs/control-agents/trusted-transfers).

## Golden rules

1. **Idempotency.** Most `POST`/`PATCH`/`DELETE` routes require an `Idempotency-Key` header (a fresh UUID per logical mutation). Retrying with the **same key and same body** replays the original response; the same key with a different body returns `idempotency_key_reuse_mismatch`. Bearer handoff is rail-aware and rechecked at the final response boundary. Legacy x402 sign is returned while `valid_before` is still strictly in the future (>0 seconds remain); at zero or when the window cannot be verified, Hightop withholds it and returns `error.details.recovery: "retry_with_new_authorization"`, so obtain a fresh authorization with a new `Idempotency-Key`. PayProcessor x402 requires at least 10 seconds and MPP requires at least 6 seconds; below those margins, or when rail/window metadata cannot be verified, obey `recovery: "do_not_retry"` and use the returned payment/on-chain evidence. The exceptions that do **not** require a key are `POST /v1/agent/simulate`, `POST /v1/agent/recipients/resolve`, `POST /v1/agent/x402/quote`, and `POST /v1/agent/mpp/quote`. Note `POST /v1/agent/conversions/quote` **does** require one (it creates a server-side quote). Each endpoint's requirement is in the Reference list.
2. **Writes are async — poll to a terminal status.** **Most** operation-backed writes return an `operation_id` with a non-terminal `status` (`submitted`/`accepted`) and only a `{ type, id }` `resource` pointer; the response is **not** a full echo of your inputs (recipient, amount, asset, vault, quote) or the final on-chain amounts. (A few finalize synchronously — x402 and MPP `sign`/`purchase`, plus a no-op deleverage, return terminal results with richer bodies.) Read the resource back (e.g. `GET /v1/agent/operations/{id}`, `GET /v1/agent/payments/{id}`) until the status is terminal (see "Operation lifecycle") to confirm what actually moved. To learn that terminal status: **subscribe to webhooks** for long-running or server-side flows, many concurrent operations, or when no process can block; **poll `GET /v1/agent/operations/{id}`** when you are driving a single operation inline and just need its result. `?wait=executed` is **not** supported in v1 — there is no synchronous wait, so use webhooks or polling.
3. **Branch on `error.code`, not on HTTP status or message text.** Errors are `{ "ok": false, "error": { "code", "message" } }` with an optional additive `details` object. The stable code set is in the Reference list.
4. **Tolerate unknown fields and enum values.** Responses are additive; ignore fields and enum members you don't recognize rather than failing.
5. **Pay through the payment rail.** To fund an approved vendor or service, call `POST /v1/agent/payments` directly. Do **not** call `earn/withdraw` or a withdrawal route first. When the agent's onchain lane allows the required payment and Earn pre-actions, payment execution can source from wallet balance and Earn positions. If `cash_usd` is near zero but `earn_usd` is funded, Hightop's owner-controlled `AUTO_DEPOSIT` automation may have moved idle funds into Earn; continue with the payment route.
6. **Respect rate limits and caps.** `429 rate_limited` carries `X-RateLimit-*` headers; protective caps return `403 limit_exceeded`. Limits per class are in the Reference list. Request bodies over 64 KB are rejected.

## Recipes

Each recipe lists its scope and whether an idempotency key is required.

### Check balances

`GET /v1/agent/balances` (scope `agent:read`). Returns cash, earn, collateral, and debt rows. For a one-line account summary use `GET /v1/agent/account`; for raw activity use `GET /v1/agent/activity`.

### Fund the wallet

`GET /v1/agent/deposit-address` (scope `agent:read`). The `asset` query parameter is required; call it with `asset=USDC&chain=base`. Agent API v1 currently returns a Base USDC deposit address. Deposits land in the same Hightop wallet the agent operates. Hightop's owner-controlled `AUTO_DEPOSIT` preference is on by default, so eligible idle deposits may move into `Core Earn`; Agent API credentials cannot change that preference. If deposited funds are held in Earn, use `POST /v1/agent/payments` directly when paying an approved recipient — do not withdraw first just to make a payment.

### Send a payment

`POST /v1/agent/payments` (scope `agent:payments:write`, idempotency **required**). Recipients must already exist (resolve one with `POST /v1/agent/recipients/resolve`). This is the normal path for funding a vendor or service; do not withdraw from Earn first. The response returns an operation id; poll `GET /v1/agent/operations/{id}` to confirm `executed`.

### Send a one-off payment

`POST /v1/agent/one-off-payments` (scope `agent:payments:write`, idempotency **required**). A **one-off payment** is a single, non-recurring payout to a recipient who is not a pre-approved recurring vendor — a controlled one-off (cheque) operation rather than an instant push transfer. In v1 you supply only `to`, `asset`, and an amount (`amount` or `amount_usd`); the timing/note modifiers in the schema (`unlock_delay_seconds`, `expires_in_seconds`, non-empty `note`) are **not** honored and a non-default value is rejected with `validation_failed`, so the operation uses server-default timing. Cancelling an active one-off payment is an owner/app-side action, not an Agent API route. Like other writes it returns only an operation id — track it via `GET /v1/agent/one-off-payments/{id}` or the `one_off_payment.*` webhook events (e.g. `one_off_payment.claimed`, `one_off_payment.expired`).

### Convert assets (quote, then execute)

1. `POST /v1/agent/conversions/quote` (scope `agent:simulate`, idempotency **required**) → a 60-second single-use `quote_id` with `expected_out`, `min_amount_out`, and slippage.
2. `POST /v1/agent/conversions` (scope `agent:conversions:write`, idempotency **required**) consuming that `quote_id`. If it returns `slippage_exceeded` or `quote_expired`, fetch a fresh quote with a new `Idempotency-Key` and retry. Same-asset conversions are rejected — use the earn routes for vault-only moves. The execute response echoes only the operation id, not `expected_out` or the realized amounts — re-read `GET /v1/agent/conversions/{id}` after it lands to see what was actually received.

### Earn

`POST /v1/agent/earn/deposit` / `POST /v1/agent/earn/withdraw` / `POST /v1/agent/earn/move` (scope `agent:earn:write`, idempotency **required**). Read current positions and APYs from `GET /v1/agent/earn` and ranked options from `GET /v1/agent/earn/opportunities`. The chosen vault is not echoed on the write response — re-read `GET /v1/agent/earn` after the operation lands.

### Borrow and repay

**GREEN** is Ripe Protocol's USD-pegged stablecoin, minted when you borrow against your collateral and burned when you repay — which is why borrow and repay are denominated in it. `POST /v1/agent/borrow` accepts only `asset: "USDC"` or `"GREEN"`; `POST /v1/agent/borrow/repay` accepts only `asset: "GREEN"` drawn from idle balance (scope `agent:borrow:write`, idempotency **required**). Unsupported assets return `asset_not_allowed` with `supported_assets` in `details`. To repay from another asset, convert to GREEN first or use `POST /v1/agent/borrow/deleverage`.

### Manage trusted destinations

A **trusted destination** is a pre-approved payout address on the agent wallet's allowlist — typically your own wallet, cold storage, a reserve address, or a linked bank — that withdrawals (`POST /v1/agent/withdrawals/to-crypto`, `POST /v1/agent/withdrawals/to-bank`) are allowed to target. Adding one is timelocked and originates from the Hightop app or control wallet, so it first appears as **pending**. From the agent API you manage that lifecycle (scope `agent:trusted_destinations:write`, idempotency **required**): `POST /v1/agent/trusted-destinations/{id}/confirm` activates a pending destination once its timelock elapses, `POST /v1/agent/trusted-destinations/{id}/cancel` drops a still-pending one, and `DELETE /v1/agent/trusted-destinations/{id}` removes an active one. List current state and status with `GET /v1/agent/trusted-destinations`.

### Pay an x402 invoice

1. `POST /v1/agent/x402/quote` (scope `agent:simulate`, **no** idempotency key) — fetches the seller URL, parses the `402` challenge, and returns the `price` without paying.
2. `POST /v1/agent/x402/purchase` (scope `agent:payments:write`, idempotency **required**) — signs and pays, bounded by your required `max_amount`. Inspect `payment_authorized`, `seller_accepted`, and `settled` for the precise outcome. To run the HTTP request yourself, use `POST /v1/agent/x402/sign` (scope `agent:payments:write`, idempotency **required**) and send the returned `payment_headers`. Only the `exact` scheme on Base USDC is supported.

For last-mile recovery, a legacy x402 sign may be returned while any positive lifetime remains. If it expires before handoff, request a fresh authorization with the required new idempotency key. PayProcessor x402 requires a 10-second handoff margin; an under-margin result is `do_not_retry` and reports `payment_id` (the on-chain bytes32 PayProcessor operation), `record_id` (the database UUID), and the Base transaction hash when known. For a legacy x402 purchase whose credential expires, only a known seller rejection permits a new authorization and key; seller acceptance or an unknown paid-request outcome is `do_not_retry`.

### Pay an MPP invoice (launch-gated)

`POST /v1/agent/mpp/quote` (scope `agent:simulate`, **no** idempotency key) probes a public HTTPS merchant for a Tempo charge without moving funds. `POST /v1/agent/mpp/purchase` (scope `agent:payments:write`, idempotency **required**) confirms a Base escrow, signs a Tempo credential, and presents it to the merchant, bounded by `max_amount`. Use `POST /v1/agent/mpp/sign` with idempotency when the caller will present the returned `authorization_header` itself. Successful sign and purchase responses always include `replayed`; `status: "originated"` describes the Base escrow, not Tempo settlement.

For purchase, `presentation_status: "accepted"` means the merchant returned HTTP 2xx plus a literal-success receipt. `presentation_status: "unknown"` means the merchant may already have received and broadcast the credential. On `unknown`, obey `seller_error.details.recovery: "do_not_retry"`: **do not re-present the credential, do not start a fresh purchase, and do not retry with a new idempotency key**. Await authoritative Base reconciliation/refund or escalate the ambiguous payment for support review.

MPP origination is disabled by default behind `MPP_ENABLED`; quote remains available. Keep sign/purchase disabled until the terminal-state-ingestion, refund-rollout, omnibus-reservation-concurrency, and auth-scoped-resume launch gates are complete.

### Receive webhooks

`POST /v1/agent/webhooks` (scope `agent:webhooks:manage`, idempotency **required**) registers a public HTTPS endpoint (max 10). The create/rotate response returns the signing secret once; verify deliveries with the `Hightop-Webhook-Signature` HMAC over `{timestamp}.{body}`. Subscribe only to the subscribable event subset (Reference list). MCP callers that can't consume `notifications/hightop/agent_webhook` should instead poll with the `agent_operations_wait_for_status` tool.

## Operation lifecycle

A write returns `status: "submitted"`; poll `GET /v1/agent/operations/{id}` until the status is one of the **terminal** statuses: `executed`, `execution_failed`, `policy_rejected`, `cancelled`. The non-terminal statuses (`accepted`, `submitted`) mean the operation is still in flight.

## Reference

> Generated from the Agent API v1 contract. Do not hand-edit — change the source contract and regenerate.

### OAuth scopes

| Scope | Capability |
| --- | --- |
| `agent:borrow:write` | Borrow, repay, deleverage, and manage collateral. |
| `agent:conversions:write` | Quote and execute conversions between supported assets. |
| `agent:earn:write` | Deposit, withdraw, move, and claim rewards in earn products. |
| `agent:payments:write` | Send payments to existing recipients and originate x402 or MPP one-off payments. |
| `agent:read` | Read balances, account, activity, and operation/resource history. |
| `agent:simulate` | Validate a write without broadcasting — request shape, static v1 contract checks, and, where applicable, owner-configured permissions and USD spend caps — and preview x402 or MPP prices. |
| `agent:trusted_destinations:write` | Confirm, cancel, and remove trusted destinations on the agent wallet allowlist. |
| `agent:webhooks:manage` | Create and manage outbound webhook endpoints. |
| `agent:withdrawals:write` | Withdraw to linked bank or trusted crypto destinations. |

### Endpoints

#### Read endpoints (41)

- `GET /v1/agent/account` — `agent:read` · rate-limit `read` — Return a scoped account summary for the authenticated agent wallet.
- `GET /v1/agent/activity` — `agent:read` · rate-limit `read` — List scoped Activity rows for the authenticated agent wallet without marking them read.
- `GET /v1/agent/assets` — `agent:read` · rate-limit `read` — List assets visible to the authenticated agent.
- `GET /v1/agent/balances` — `agent:read` · rate-limit `read` — List balances for the authenticated agent wallet.
- `GET /v1/agent/balances/cash` — `agent:read` · rate-limit `read` — List cash balances for the authenticated agent wallet.
- `GET /v1/agent/borrow` — `agent:read` · rate-limit `read` — Return borrow summary for the authenticated agent wallet.
- `GET /v1/agent/borrow/collateral` — `agent:read` · rate-limit `read` — List collateral for the authenticated agent wallet.
- `GET /v1/agent/borrow/collateral-options` — `agent:read` · rate-limit `read` — List addable collateral options for the authenticated agent wallet.
- `GET /v1/agent/capabilities` — `agent:read` · rate-limit `read` — Return Agent API capabilities for the authenticated agent.
- `GET /v1/agent/capabilities.json` — `agent:read` · rate-limit `read` — Return Agent API capabilities as JSON.
- `GET /v1/agent/conversions` — `agent:read` · rate-limit `read` — List conversion operations for the authenticated agent.
- `GET /v1/agent/conversions/{id}` — `agent:read` · rate-limit `read` — Get one conversion operation for the authenticated agent.
- `GET /v1/agent/deposit-address` — `agent:read` · rate-limit `read` — Return a Base deposit address for an asset.
- `GET /v1/agent/deposit-methods` — `agent:read` · rate-limit `read` — List deposit methods for the authenticated agent wallet.
- `GET /v1/agent/earn` — `agent:read` · rate-limit `read` — List earn positions for the authenticated agent wallet.
- `GET /v1/agent/earn/{id}` — `agent:read` · rate-limit `read` — Get one earn position for the authenticated agent wallet.
- `GET /v1/agent/earn/opportunities` — `agent:read` · rate-limit `read` — List earn opportunities available to the authenticated agent.
- `GET /v1/agent/one-off-payments` — `agent:read` · rate-limit `read` — List one-off payment operations for the authenticated agent.
- `GET /v1/agent/one-off-payments/{id}` — `agent:read` · rate-limit `read` — Get a one-off payment operation for the authenticated agent.
- `GET /v1/agent/operations` — `agent:read` · rate-limit `read` — List AgentOperation rows for the authenticated agent.
- `GET /v1/agent/operations/{id}` — `agent:read` · rate-limit `read` — Get one AgentOperation for the authenticated agent.
- `GET /v1/agent/payments` — `agent:read` · rate-limit `read` — List payment operations for the authenticated agent.
- `GET /v1/agent/payments/{id}` — `agent:read` · rate-limit `read` — Get one payment operation for the authenticated agent.
- `GET /v1/agent/protocols` — `agent:read` · rate-limit `read` — List protocols visible to the authenticated agent.
- `GET /v1/agent/recipients` — `agent:read` · rate-limit `read` — List payment recipients visible to the authenticated agent wallet.
- `GET /v1/agent/recipients/{id}` — `agent:read` · rate-limit `read` — Get one recipient visible to the authenticated agent wallet.
- `GET /v1/agent/recurring-payments` — `agent:read` · rate-limit `read` — List recurring payment recipients visible to the authenticated agent wallet.
- `GET /v1/agent/recurring-payments/{id}` — `agent:read` · rate-limit `read` — Get one recurring payment recipient visible to the authenticated agent wallet.
- `GET /v1/agent/self` — `agent:read` · rate-limit `read` — Return the authenticated agent and scoped wallet context.
- `GET /v1/agent/self/limits` — `agent:read` · rate-limit `read` — Return effective operation permissions, spend/swap limits, and current-period usage for the authenticated agent.
- `GET /v1/agent/self/usage` — `agent:read` · rate-limit `read` — Return current Agent API rate-limit and usage state.
- `GET /v1/agent/trusted-destinations` — `agent:read` · rate-limit `read` — List trusted destinations visible to the authenticated agent wallet.
- `GET /v1/agent/trusted-destinations/{id}` — `agent:read` · rate-limit `read` — Get one trusted destination visible to the authenticated agent wallet.
- `GET /v1/agent/vendors` — `agent:read` · rate-limit `read` — List vendors in the payment routing registry.
- `GET /v1/agent/vendors/{domain}` — `agent:read` · rate-limit `read` — Get one vendor by domain, including its on-chain destination allowlist.
- `GET /v1/agent/webhooks` — `agent:read` · rate-limit `webhook_management` — List outbound webhook endpoints for the authenticated agent.
- `GET /v1/agent/webhooks/{id}` — `agent:read` · rate-limit `webhook_management` — Get one outbound webhook endpoint for the authenticated agent.
- `GET /v1/agent/webhooks/{id}/deliveries` — `agent:read` · rate-limit `read` — List webhook delivery attempts for one outbound webhook endpoint.
- `GET /v1/agent/withdrawal-methods` — `agent:read` · rate-limit `read` — List withdrawal methods visible to the authenticated agent wallet.
- `GET /v1/agent/withdrawals` — `agent:read` · rate-limit `read` — List withdrawal operations for the authenticated agent.
- `GET /v1/agent/withdrawals/{id}` — `agent:read` · rate-limit `read` — Get one withdrawal operation for the authenticated agent.

#### Write and simulation endpoints (31)

- `POST /v1/agent/borrow` — `agent:borrow:write` · rate-limit `write` · idempotency required — Create a borrow operation for USDC or GREEN.
- `POST /v1/agent/borrow/collateral/add` — `agent:borrow:write` · rate-limit `write` · idempotency required — Create a collateral add operation.
- `POST /v1/agent/borrow/collateral/remove` — `agent:borrow:write` · rate-limit `write` · idempotency required — Create a collateral remove operation.
- `POST /v1/agent/borrow/deleverage` — `agent:borrow:write` · rate-limit `write` · idempotency required — Create a target-LTV deleverage operation.
- `POST /v1/agent/borrow/repay` — `agent:borrow:write` · rate-limit `write` · idempotency required — Create a debt repayment operation.
- `POST /v1/agent/conversions` — `agent:conversions:write` · rate-limit `write` · idempotency required — Execute a conversion from a quote.
- `POST /v1/agent/conversions/quote` — `agent:simulate` · rate-limit `simulate` · idempotency required — Create a stateful conversion quote.
- `POST /v1/agent/earn/deposit` — `agent:earn:write` · rate-limit `write` · idempotency required — Create an earn deposit operation.
- `POST /v1/agent/earn/move` — `agent:earn:write` · rate-limit `write` · idempotency required — Create an earn move operation.
- `POST /v1/agent/earn/rewards/claim` — `agent:earn:write` · rate-limit `write` · idempotency required — Create a rewards claim operation.
- `POST /v1/agent/earn/withdraw` — `agent:earn:write` · rate-limit `write` · idempotency required — Create an earn withdrawal operation.
- `POST /v1/agent/mpp/purchase` — `agent:payments:write` · rate-limit `write` · idempotency required — Originate + sign an MPP (Tempo) charge, present the credential to the merchant, and return the receipt.
- `POST /v1/agent/mpp/quote` — `agent:simulate` · rate-limit `simulate` — Fetch a URL and return its supported MPP (Tempo) charge price without paying.
- `POST /v1/agent/mpp/sign` — `agent:payments:write` · rate-limit `write` · idempotency required — Originate and sign an MPP (Tempo) charge, returning the Authorization: Payment credential to present to the merchant.
- `POST /v1/agent/one-off-payments` — `agent:payments:write` · rate-limit `write` · idempotency required — Create a one-off payment operation.
- `POST /v1/agent/payments` — `agent:payments:write` · rate-limit `write` · idempotency required — Create a payment operation.
- `POST /v1/agent/recipients/resolve` — `agent:read` · rate-limit `read` — Resolve an agent-facing recipient identifier.
- `POST /v1/agent/simulate` — `agent:simulate` · rate-limit `simulate` — Simulate a write request without broadcasting.
- `DELETE /v1/agent/trusted-destinations/{id}` — `agent:trusted_destinations:write` · rate-limit `write` · idempotency required — Remove a trusted destination from the authenticated agent wallet.
- `POST /v1/agent/trusted-destinations/{id}/cancel` — `agent:trusted_destinations:write` · rate-limit `write` · idempotency required — Cancel a pending trusted destination for the authenticated agent wallet.
- `POST /v1/agent/trusted-destinations/{id}/confirm` — `agent:trusted_destinations:write` · rate-limit `write` · idempotency required — Confirm a pending trusted destination for the authenticated agent wallet.
- `POST /v1/agent/webhooks` — `agent:webhooks:manage` · rate-limit `webhook_management` · idempotency required — Create an outbound webhook endpoint.
- `PATCH /v1/agent/webhooks/{id}` — `agent:webhooks:manage` · rate-limit `webhook_management` · idempotency required — Update an outbound webhook endpoint.
- `DELETE /v1/agent/webhooks/{id}` — `agent:webhooks:manage` · rate-limit `webhook_management` · idempotency required — Delete or disable an outbound webhook endpoint.
- `POST /v1/agent/webhooks/{id}/rotate-secret` — `agent:webhooks:manage` · rate-limit `webhook_management` · idempotency required — Rotate an outbound webhook signing secret.
- `POST /v1/agent/webhooks/{id}/test` — `agent:webhooks:manage` · rate-limit `webhook_management` · idempotency required — Send a webhook.test delivery to an outbound webhook endpoint.
- `POST /v1/agent/withdrawals/to-bank` — `agent:withdrawals:write` · rate-limit `write` · idempotency required — Create a bank withdrawal operation.
- `POST /v1/agent/withdrawals/to-crypto` — `agent:withdrawals:write` · rate-limit `write` · idempotency required — Create a crypto withdrawal operation.
- `POST /v1/agent/x402/purchase` — `agent:payments:write` · rate-limit `write` · idempotency required — Fetch a URL, satisfy an x402 challenge when required, and return the upstream response.
- `POST /v1/agent/x402/quote` — `agent:simulate` · rate-limit `simulate` — Fetch a URL and return its supported x402 price without paying.
- `POST /v1/agent/x402/sign` — `agent:payments:write` · rate-limit `write` · idempotency required — Sign a Base USDC x402 payment authorization from an x402 payment requirement.

### Error codes

Branch on `error.code`. Reserved codes are part of the contract but not currently emitted; keep handling them.

| HTTP | Codes |
| --- | --- |
| 400 | validation_failed, signature_expired, signature_invalid_s |
| 401 | authentication_failed, agent_disabled, agent_not_yet_active, agent_expired |
| 403 | owner_only_action, identity_gated_action, permission_not_granted, insufficient_scope, asset_not_allowed, recipient_not_allowed, protocol_not_allowed, limit_exceeded, cooldown_active (reserved), ltv_too_high, operation_feature_disabled |
| 404 | not_found, cheque_not_found |
| 409 | quote_expired, quote_already_consumed, signature_invalid_nonce, one_off_payment_not_active, one_off_payment_stale, one_off_payment_replaced, one_off_payment_already_paid, cheque_replaced, starter_agent_not_removable, pending_one_off_payment_settings_exists, pending_one_off_payment_settings_missing, pending_time_lock_exists, time_delay_not_reached, owner_changed_pending_state, migration_blocked_pending_one_off_payment_settings, migration_blocked_pending_time_lock, loot_not_available, timelock_not_elapsed (reserved), ltv_target_unreachable, idempotency_key_reuse_mismatch, idempotency_request_in_progress, rule_changed_during_execution (reserved), operation_not_cancellable, operation_not_supported_for_wrapper_version |
| 422 | insufficient_funds, slippage_exceeded, price_stale, invalid_pull_one_off_payment_flags |
| 429 | rate_limited |
| 500 | internal_error |
| 502 | execution_failed, execution_timeout, batch_step_failed (reserved) |
| 503 | agent_api_cutover_in_progress, agent_api_chain_unavailable |

### Operation statuses

All: `accepted`, `policy_rejected`, `submitted`, `executed`, `execution_failed`, `cancelled`. Terminal: `executed`, `execution_failed`, `policy_rejected`, `cancelled`.

### Webhook events

Subscribe only to the **subscribable** subset — only those can be registered on an endpoint. The full list is the complete event vocabulary; the remaining types are **reserved** — advertised for forward-compatibility but not emitted by any shipped v1 producer yet, and rejected if included on a webhook create/update. Both lists are grouped by domain.

**Subscribable (25)** — register these on a webhook endpoint:

- **Payments:** `payment.executed`, `payment.execution_failed`
- **One-off payments:** `one_off_payment.created`, `one_off_payment.claimed`, `one_off_payment.expired`, `one_off_payment.execution_failed`
- **Conversions:** `conversion.executed`, `conversion.execution_failed`
- **Earn & rewards:** `earn.deposit.executed`, `earn.withdraw.executed`, `earn.move.executed`, `rewards.claimed`
- **Borrow:** `debt.borrowed`, `debt.repaid`, `debt.deleveraged`, `collateral.added`, `collateral.removed`
- **Withdrawals & deposits:** `withdrawal.settled`, `withdrawal.execution_failed`
- **Trusted destinations:** `trusted_destination.confirmed`, `trusted_destination.cancelled`, `trusted_destination.removed`
- **Agent & account:** `agent.webhook_disabled`
- **System:** `operation.policy_rejected`, `webhook.test`

<details>
<summary><strong>All event types (56)</strong> — the complete vocabulary, including reserved types not emitted in v1</summary>

- **Payments:** `payment.submitted`, `payment.executed`, `payment.execution_failed`, `payment.received`, `recurring_payment.updated`, `recipient.changed`
- **One-off payments:** `one_off_payment.created`, `one_off_payment.claimed`, `one_off_payment.expired`, `one_off_payment.execution_failed`, `one_off_payment.pay_failed.stale`, `one_off_payment.pay_failed.replaced`, `one_off_payment.pay_failed.already_paid`, `one_off_payment.pay_failed.inactive`, `one_off_payment.pull_issued`, `one_off_payment.pull_child_created`, `one_off_payment.harvest_and_created`, `one_off_payment.harvest_and_create_failed`, `one_off_payment_settings.pending_set`, `one_off_payment_settings.confirmed`, `one_off_payment_settings.cancelled`
- **Conversions:** `conversion.executed`, `conversion.execution_failed`
- **Earn & rewards:** `earn.deposit.executed`, `earn.withdraw.executed`, `earn.move.executed`, `rewards.claimed`, `loot.claimed_all`, `loot.claimed_revshare`, `loot.claimed_deposit_rewards`
- **Borrow:** `debt.borrowed`, `debt.repaid`, `debt.deleveraged`, `collateral.added`, `collateral.removed`
- **Withdrawals & deposits:** `withdrawal.submitted`, `withdrawal.settled`, `withdrawal.execution_failed`, `deposit.received`
- **Trusted destinations:** `trusted_destination.confirmed`, `trusted_destination.cancelled`, `trusted_destination.removed`, `trusted_destination.maintenance.executed`, `trusted_destination.maintenance.failed`
- **Agent & account:** `agent.self_removed`, `agent.limit_approaching`, `agent.limit_reached`, `agent.disabled`, `agent.expired`, `agent.expiring_soon`, `agent.webhook_disabled`, `time_lock.pending_set`, `time_lock.confirmed`, `time_lock.cancelled`
- **System:** `operation.policy_rejected`, `webhook.test`

</details>

### Rate-limit classes

| Class | Limit | Burst | Window (s) |
| --- | --- | --- | --- |
| `bulk_write` | 20 | 5 | 60 |
| `read` | 600 | 100 | 60 |
| `simulate` | 120 | 30 | 60 |
| `webhook_management` | 10 | 5 | 60 |
| `write` | 60 | 20 | 60 |

## Going deeper

- Machine contract: public `GET /v1/agent/openapi.json`; authenticated `GET /v1/agent/capabilities.json`.
- Packages: `@hightop/sdk` (typed client) and `@hightop/cli` (the `hightop` CLI) — see each package's README.
- In the hightop-api repository (not fetchable URLs): `docs/agent-api/public.md` (full human contract), `docs/agent-api/mcp-endpoint.md`, and `docs/agent-api/webhooks.md`.
