# Agentic Payments — API Reference

All 54 endpoints under `https://api.aureahub.com/v1/agent-payments`. Unless noted, every route requires a tenant-admin JWT (a platform `admin` may add `?tenantId=` to act on a tenant). The shopper-facing commerce routes also accept a scoped merchant API key; the only unauthenticated route is the payment provider's own callback, which you never call.

> ℹ️ Monetary amounts are decimal strings (e.g. `"49.90"`). The card refund route (`POST /commerce/checkout/:id/refund`) uses `amountMinor` (an integer in the smallest currency unit). All `:id` path parameters are UUIDs.

## Agents

### `POST /v1/agent-payments/agents`

Authentication: bearer token required.

Create an agent identity (merchant, spending, machine, or external) scoped to the caller's tenant.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Display name (1–255 chars) |
| `description` | string | no | Up to 2000 chars |
| `agentType` | enum | no | internal \| merchant \| external \| machine |
| `did` | string | no | Decentralised identifier (up to 255 chars) |
| `publicKey` | string | no | Agent public key (for signed mandates) |
| `userId` | uuid | no | Link the agent to a specific user |
| `metadata` | object | no | Arbitrary JSON metadata |
| `isTestnet` | boolean | no | Mark the agent as testnet-only |

**Responses**

`201` Created

```json
{
  "id": "11111111-1111-1111-1111-111111111111",
  "tenantId": "22222222-2222-2222-2222-222222222222",
  "userId": null,
  "did": null,
  "name": "Acme Storefront Agent",
  "description": null,
  "agentType": "merchant",
  "status": "active",
  "publicKey": null,
  "verifiedAgentId": null,
  "metadata": {},
  "isTestnet": false,
  "createdAt": "2026-06-24T10:00:00.000Z",
  "updatedAt": "2026-06-24T10:00:00.000Z"
}
```

`422` Validation Error

```json
{ "detail": "Validation failed", "errors": [ { "path": ["name"], "message": "Required" } ] }
```

`404` Module Disabled

```json
{ "detail": "Agent payments module is not enabled for this deployment" }
```

**Example request**

```bash
curl -X POST https://api.aureahub.com/v1/agent-payments/agents \
  -H "Authorization: Bearer YOUR_TENANT_ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme Storefront Agent", "agentType": "merchant" }'
```

### `GET /v1/agent-payments/agents`

Authentication: bearer token required.

List agents for the caller's tenant, optionally filtered by status with pagination.

**Query parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | no | 1–200 |
| `offset` | integer | no | Zero-based offset |
| `status` | enum | no | pending \| active \| suspended \| revoked |

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "11111111-1111-1111-1111-111111111111",
      "name": "Acme Storefront Agent",
      "agentType": "merchant",
      "status": "active",
      "isTestnet": false,
      "createdAt": "2026-06-24T10:00:00.000Z"
    }
  ]
}
```

**Example request**

```bash
curl "https://api.aureahub.com/v1/agent-payments/agents?status=active&limit=50" \
  -H "Authorization: Bearer YOUR_TENANT_ADMIN_JWT"
```

### `GET /v1/agent-payments/agents/:id`

Authentication: bearer token required.

Fetch a single agent by id within the caller's tenant.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Responses**

`200` OK

```json
{
  "id": "11111111-1111-1111-1111-111111111111",
  "name": "Acme Storefront Agent",
  "agentType": "merchant",
  "status": "active",
  "metadata": {},
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

`404` Not Found

```json
{ "detail": "Agent not found" }
```

### `DELETE /v1/agent-payments/agents/:id`

Authentication: bearer token required.

Soft-delete an agent: revoke its active API keys, then mark it revoked. Execution/audit history is preserved.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Responses**

`200` OK

```json
{
  "id": "11111111-1111-1111-1111-111111111111",
  "name": "Acme Storefront Agent",
  "status": "revoked",
  "updatedAt": "2026-06-24T11:00:00.000Z"
}
```

`404` Not Found

```json
{ "detail": "Agent not found" }
```

### `POST /v1/agent-payments/agents/provision-merchant`

Authentication: bearer token required.

One-call merchant provisioning (for integrations like Aurea Pay): creates a merchant agent plus a publishable key. The publishable key is returned in full exactly once.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Merchant display name (1–255 chars) |
| `externalRef` | string | no | Your own reference id, stored in agent metadata |
| `allowedOrigins` | string[] | no | Origins permitted to use the publishable key (max 20) |
| `label` | string | no | Label for the issued key (defaults to "widget") |

**Responses**

`201` Created

```json
{
  "agent": {
    "id": "11111111-1111-1111-1111-111111111111",
    "name": "Acme",
    "agentType": "merchant",
    "status": "active"
  },
  "publishableKey": {
    "id": "33333333-3333-3333-3333-333333333333",
    "agentId": "11111111-1111-1111-1111-111111111111",
    "keyType": "publishable",
    "key": "apk_live_9f8e7d6c5b4a...",
    "publicKey": "apk_live_9f8e7d6c5b4a...",
    "last4": "4a3b",
    "allowedOrigins": ["https://acme.example"],
    "label": "widget",
    "status": "active",
    "createdAt": "2026-06-24T10:00:00.000Z"
  }
}
```

## API Keys

### `POST /v1/agent-payments/agents/:id/api-keys`

Authentication: bearer token required.

Issue a scoped API key for an agent. The full key is returned exactly once; only a last4 is stored thereafter.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `keyType` | enum | yes | publishable \| secret |
| `label` | string | no | Up to 120 chars |
| `allowedOrigins` | string[] | no | Origins permitted (publishable keys; max 20) |

**Responses**

`201` Created

```json
{
  "id": "33333333-3333-3333-3333-333333333333",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "keyType": "secret",
  "key": "ask_live_a1b2c3d4e5f6...",
  "publicKey": null,
  "last4": "e5f6",
  "allowedOrigins": [],
  "label": "server",
  "status": "active",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

### `GET /v1/agent-payments/agents/:id/api-keys`

Authentication: bearer token required.

List API keys for an agent. Secret keys never expose the full key — only last4.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "33333333-3333-3333-3333-333333333333",
      "agentId": "11111111-1111-1111-1111-111111111111",
      "keyType": "publishable",
      "publicKey": "apk_live_9f8e7d6c...",
      "last4": "4a3b",
      "allowedOrigins": ["https://acme.example"],
      "label": "widget",
      "status": "active",
      "createdAt": "2026-06-24T10:00:00.000Z"
    }
  ]
}
```

### `POST /v1/agent-payments/api-keys/:id/rotate`

Authentication: bearer token required.

Rotate an API key: issue a new secret with the same scope and retire the old one. The new full key is returned exactly once.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | API key id |

**Responses**

`200` OK

```json
{
  "id": "33333333-3333-3333-3333-333333333333",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "keyType": "secret",
  "key": "ask_live_NEWKEY...",
  "publicKey": null,
  "last4": "9z8y",
  "status": "active",
  "createdAt": "2026-06-24T12:00:00.000Z"
}
```

### `POST /v1/agent-payments/api-keys/:id/revoke`

Authentication: bearer token required.

Revoke an API key immediately so it can no longer authenticate.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | API key id |

**Responses**

`200` OK

```json
{ "id": "33333333-3333-3333-3333-333333333333", "status": "revoked" }
```

### `PUT /v1/agent-payments/api-keys/:id/origins`

Authentication: bearer token required.

Replace the allowed-origins allow-list for a (publishable) API key.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | API key id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `allowedOrigins` | string[] | yes | Full replacement list of allowed origins (max 20) |

**Responses**

`200` OK

```json
{ "id": "33333333-3333-3333-3333-333333333333", "allowedOrigins": ["https://acme.example", "https://shop.acme.example"] }
```

## Policies

### `POST /v1/agent-payments/policies`

Authentication: bearer token required.

Create a spending policy (limits, allow/deny lists, optional validity window) used by the PolicyGuard to authorize agent payments.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Agent this policy governs |
| `name` | string | yes | 1–255 chars |
| `currency` | string | no | Limit currency (up to 20 chars) |
| `perTxMax` | decimal | no | Max per-transaction amount (decimal string) |
| `dailyMax` | decimal | no | Max per rolling day |
| `weeklyMax` | decimal | no | Max per rolling week |
| `monthlyMax` | decimal | no | Max per rolling month |
| `velocityMaxCount` | integer | no | Max transactions per velocity window |
| `velocityWindowSeconds` | integer | no | Velocity window length, seconds |
| `allowedAssets` | string[] | no | Permitted assets |
| `allowedChains` | string[] | no | Permitted chains |
| `recipientAllowlist` | string[] | no | Only these recipients may be paid |
| `recipientBlocklist` | string[] | no | These recipients are denied |
| `stepUpThreshold` | decimal | no | Amount above which step-up is required |
| `requiresApproval` | boolean | no | Force manual approval for every payment |
| `notBefore` | datetime | no | ISO 8601; policy inactive before this |
| `expiresAt` | datetime | no | ISO 8601; policy inactive after this |
| `metadata` | object | no | Arbitrary JSON metadata |

**Responses**

`201` Created

```json
{
  "id": "44444444-4444-4444-4444-444444444444",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "name": "Default storefront policy",
  "status": "active",
  "currency": "EUR",
  "perTxMax": "250.00",
  "dailyMax": "1000.00",
  "weeklyMax": null,
  "monthlyMax": null,
  "velocityMaxCount": null,
  "velocityWindowSeconds": null,
  "allowedAssets": [],
  "allowedChains": [],
  "recipientAllowlist": [],
  "recipientBlocklist": [],
  "stepUpThreshold": "200.00",
  "requiresApproval": false,
  "notBefore": null,
  "expiresAt": null,
  "metadata": {},
  "createdAt": "2026-06-24T10:00:00.000Z",
  "updatedAt": "2026-06-24T10:00:00.000Z"
}
```

## Mandates

### `POST /v1/agent-payments/mandates`

Authentication: bearer token required.

Create a signed agent mandate — the user-authorized spending grant an agent acts under (intent, cart, or recurring).

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Agent the mandate is for |
| `mandateType` | enum | yes | intent \| cart \| recurring |
| `userId` | uuid | no | Authorizing user |
| `walletId` | uuid | no | Source wallet |
| `policyId` | uuid | no | Policy that bounds this mandate |
| `parentMandateId` | uuid | no | Parent mandate (for sub-mandates) |
| `description` | string | no | Up to 2000 chars |
| `maxAmount` | decimal | no | Maximum spend under the mandate |
| `currency` | string | no | Up to 20 chars |
| `asset` | string | no | Up to 100 chars |
| `chain` | string | no | Up to 50 chars |
| `merchant` | string | no | Bound merchant (up to 255 chars) |
| `cart` | object | no | Cart snapshot (cart mandates) |
| `constraints` | object | no | Additional JSON constraints |
| `recurrenceRule` | string | no | Recurrence rule (up to 255 chars) |
| `recurrenceIntervalSeconds` | integer | no | Interval between runs, seconds |
| `nextRunAt` | datetime | no | ISO 8601; first/next run time |
| `maxRuns` | integer | no | Cap on total runs |
| `notBefore` | datetime | no | ISO 8601 validity start |
| `expiresAt` | datetime | no | ISO 8601 validity end |
| `signature` | string | no | Detached signature over the mandate hash |
| `signedBy` | enum | no | user \| agent |

**Responses**

`201` Created

```json
{
  "id": "55555555-5555-5555-5555-555555555555",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "mandateType": "recurring",
  "status": "active",
  "maxAmount": "100.00",
  "currency": "EUR",
  "recurrenceIntervalSeconds": 2592000,
  "nextRunAt": "2026-07-24T09:00:00.000Z",
  "runCount": 0,
  "maxRuns": 12,
  "signedBy": "user",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

### `GET /v1/agent-payments/mandates/:id`

Authentication: bearer token required.

Fetch a single mandate by id within the caller's tenant.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Mandate id |

**Responses**

`200` OK

```json
{
  "id": "55555555-5555-5555-5555-555555555555",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "mandateType": "cart",
  "status": "active",
  "maxAmount": "49.90",
  "currency": "EUR",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

`404` Not Found

```json
{ "detail": "Mandate not found" }
```

### `POST /v1/agent-payments/mandates/:id/revoke`

Authentication: bearer token required.

Revoke a mandate so the agent can no longer act under it.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Mandate id |

**Responses**

`200` OK

```json
{
  "id": "55555555-5555-5555-5555-555555555555",
  "status": "revoked",
  "updatedAt": "2026-06-24T11:00:00.000Z"
}
```

### `POST /v1/agent-payments/mandates/:id/verify`

Authentication: bearer token required.

Verify a mandate's validity (signature / status / expiry). Read-only — moves no money.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Mandate id |

**Responses**

`200` Valid

```json
{ "valid": true }
```

`200` Invalid

```json
{ "valid": false, "reason": "Mandate expired" }
```

## Authorize & Executions

### `POST /v1/agent-payments/authorize`

Authentication: bearer token required.

Preview a policy decision: evaluate a proposed payment against the PolicyGuard and return allow / deny / step-up / approval-required with its trace. Moves no money.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Agent making the payment |
| `mandateId` | uuid | no | Mandate the payment is under |
| `policyId` | uuid | no | Policy to evaluate against |
| `walletId` | uuid | no | Source wallet |
| `amount` | decimal | no | Proposed amount |
| `currency` | string | no | Up to 20 chars |
| `asset` | string | no | Up to 100 chars |
| `chain` | string | no | Up to 50 chars |
| `recipient` | string | no | Proposed recipient |
| `kind` | string | no | Payment kind (up to 50 chars) |
| `idempotencyKey` | string | no | Up to 255 chars |

**Responses**

`200` Allow

```json
{
  "allow": true,
  "reason": "within policy",
  "requiresStepUp": false,
  "requiresApproval": false,
  "riskScore": 12,
  "trace": { "reservationId": "66666666-6666-6666-6666-666666666666" }
}
```

`200` Deny

```json
{
  "allow": false,
  "reason": "perTxMax exceeded",
  "riskScore": 80
}
```

### `POST /v1/agent-payments/executions`

Authentication: bearer token required.

Execute an agent payment through the policy gate: authorize (reserving on the spend ledger), then move money on the chosen rail. Idempotent by key. Decisions needing step-up/approval are parked as approval_required.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Agent making the payment |
| `mandateId` | uuid | no | Mandate the payment is under |
| `policyId` | uuid | no | Policy to evaluate against |
| `walletId` | uuid | no | Source wallet |
| `amount` | decimal | yes | Amount (decimal string) |
| `currency` | string | yes | 1–20 chars |
| `asset` | string | no | Up to 100 chars |
| `chain` | string | no | Up to 50 chars |
| `recipient` | string | yes | Recipient (1–255 chars) |
| `kind` | enum | no | payment \| payout \| swap \| redeem \| x402 \| refund |
| `idempotencyKey` | string | no | Up to 255 chars |

**Responses**

`201` Settled

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "kind": "payment",
  "rail": "onchain",
  "status": "settled",
  "amount": "49.90",
  "currency": "EUR",
  "recipient": "0xRecipient...",
  "policyDecision": { "allow": true, "reason": "within policy" },
  "riskScore": 12,
  "idempotencyKey": "order-1001",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

`201` Approval Required

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "status": "approval_required",
  "amount": "500.00",
  "currency": "EUR",
  "policyDecision": { "allow": false, "requiresApproval": true, "reason": "above approval threshold" }
}
```

### `POST /v1/agent-payments/executions/:id/approve`

Authentication: bearer token required.

Approve an execution parked as approval_required, releasing it to complete on the rail (the held reservation is settled).

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Execution id |

**Responses**

`200` OK

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "status": "settled",
  "amount": "500.00",
  "currency": "EUR",
  "updatedAt": "2026-06-24T11:00:00.000Z"
}
```

## Approvals (agent-requests)

### `GET /v1/agent-payments/agent-requests`

Authentication: bearer token required.

List pending deferred-approval requests (executions awaiting a human decision) for the tenant.

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "77777777-7777-7777-7777-777777777777",
      "status": "pending",
      "display": {
        "title": "Approve payment of EUR 500.00",
        "sections": [ { "label": "Recipient", "value": "0xRecipient..." } ]
      },
      "result": null,
      "amount": "500.00",
      "currency": "EUR",
      "recipient": "0xRecipient...",
      "agentId": "11111111-1111-1111-1111-111111111111",
      "createdAt": "2026-06-24T10:00:00.000Z",
      "expiresAt": "2026-06-25T10:00:00.000Z"
    }
  ]
}
```

### `GET /v1/agent-payments/agent-requests/:id`

Authentication: bearer token required.

Fetch a single deferred-approval request by id.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent request (execution) id |

**Responses**

`200` OK

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "status": "pending",
  "display": { "title": "Approve payment of EUR 500.00", "sections": [] },
  "amount": "500.00",
  "currency": "EUR",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

`404` Not Found

```json
{ "error": "not found" }
```

### `POST /v1/agent-payments/agent-requests/:id/approve`

Authentication: bearer token required.

Approve a deferred-approval request, releasing the underlying execution to complete on the rail.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent request (execution) id |

**Responses**

`200` OK

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "status": "settled",
  "updatedAt": "2026-06-24T11:00:00.000Z"
}
```

### `POST /v1/agent-payments/agent-requests/:id/reject`

Authentication: bearer token required.

Reject a deferred-approval request with an optional reason; the underlying execution is declined and its held reservation released.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent request (execution) id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | no | Optional rejection reason (up to 500 chars) |

**Responses**

`200` OK

```json
{
  "id": "77777777-7777-7777-7777-777777777777",
  "status": "denied",
  "denialReason": "out of budget",
  "updatedAt": "2026-06-24T11:00:00.000Z"
}
```

## Commerce — Catalog & Ingest

### `POST /v1/agent-payments/commerce/feed`

Authentication: bearer token required.

Ingest a structured product feed for a merchant agent (1–1000 items). Returns the number of products ingested.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Merchant agent |
| `items` | object[] | yes | 1–1000 product items (see fields below) |
| `items[].sku` | string | yes | 1–255 chars |
| `items[].name` | string | yes | 1–255 chars |
| `items[].price` | decimal | yes | Decimal string |
| `items[].currency` | string | yes | 1–20 chars |
| `items[].description` | string | no | Up to 2000 chars |
| `items[].imageUrl` | url | no | Product image URL |
| `items[].metadata` | object | no | Arbitrary JSON metadata |
| `items[].active` | boolean | no | Whether the item is purchasable |

**Responses**

`200` OK

```json
{ "ingested": 42 }
```

### `POST /v1/agent-payments/commerce/ingest-url`

Authentication: bearer token required.

Crawl a merchant storefront URL and ingest its catalogue (detects a JSON feed, Shopify products, or JSON-LD). Explicit, not automatic.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Merchant agent |
| `url` | url | yes | Storefront URL to crawl (up to 2048 chars) |

**Responses**

`200` OK

```json
{ "ingested": 42, "source": "shopify" }
```

### `GET /v1/agent-payments/commerce/products`

Authentication: bearer token required.

List a merchant agent's ingested products. Accepts a scoped merchant API key (the key pins the agent) OR a tenant-admin JWT.

**Query parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Merchant agent (ignored when a publishable key pins the agent) |

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "88888888-8888-8888-8888-888888888888",
      "agentId": "11111111-1111-1111-1111-111111111111",
      "sku": "TEE-001",
      "name": "Cotton Tee",
      "description": "100% organic cotton",
      "price": "24.90",
      "currency": "EUR",
      "imageUrl": "https://acme.example/img/tee.jpg",
      "active": true
    }
  ]
}
```

**Example request**

```bash
curl "https://api.aureahub.com/v1/agent-payments/commerce/products?agentId=AGENT_UUID" \
  -H "X-Aurea-Key: apk_live_..."
```

## Commerce — Checkout

### `POST /v1/agent-payments/commerce/checkout`

Authentication: bearer token required.

Create a checkout session (locked as a cart mandate) from cart items. Accepts a scoped merchant API key OR a tenant-admin JWT.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Merchant agent (ignored when a publishable key pins the agent) |
| `items` | object[] | yes | Cart line items (min 1) |
| `items[].sku` | string | yes | 1–255 chars |
| `items[].quantity` | integer | yes | Positive integer |
| `currency` | string | no | Up to 20 chars |

**Responses**

`201` Created

```json
{
  "checkoutId": "99999999-9999-9999-9999-999999999999",
  "status": "active",
  "currency": "EUR",
  "total": "49.80",
  "items": [
    { "sku": "TEE-001", "name": "Cotton Tee", "quantity": 2, "unitPrice": "24.90", "lineTotal": "49.80" }
  ],
  "agentId": "11111111-1111-1111-1111-111111111111"
}
```

**Example request**

```bash
curl -X POST https://api.aureahub.com/v1/agent-payments/commerce/checkout \
  -H "X-Aurea-Key: apk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "agentId": "AGENT_UUID", "items": [ { "sku": "TEE-001", "quantity": 2 } ] }'
```

### `GET /v1/agent-payments/commerce/checkout/:id`

Authentication: bearer token required.

Fetch a checkout session by id. Accepts a scoped merchant API key OR a tenant-admin JWT.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Checkout id (== cart mandate id) |

**Responses**

`200` OK

```json
{
  "checkoutId": "99999999-9999-9999-9999-999999999999",
  "status": "active",
  "currency": "EUR",
  "total": "49.80",
  "items": [
    { "sku": "TEE-001", "name": "Cotton Tee", "quantity": 2, "unitPrice": "24.90", "lineTotal": "49.80" }
  ],
  "agentId": "11111111-1111-1111-1111-111111111111"
}
```

### `POST /v1/agent-payments/commerce/checkout/:id/complete`

Authentication: bearer token required.

Complete a checkout: execute the cart-mandate payment through the policy gate and record split settlement legs (merchant / platform / tax / fee). Tenant-admin JWT only.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Checkout id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `recipient` | string | yes | Primary payout recipient (1–255 chars) |
| `walletId` | uuid | no | Source wallet |
| `splits` | object[] | no | Optional split settlement legs |
| `splits[].partyType` | enum | no | merchant \| platform \| tax \| fee \| other |
| `splits[].recipient` | string | no | Leg recipient (1–255 chars) |
| `splits[].amount` | decimal | no | Leg amount (decimal string) |

**Responses**

`200` OK

```json
{
  "checkoutId": "99999999-9999-9999-9999-999999999999",
  "execution": {
    "id": "77777777-7777-7777-7777-777777777777",
    "kind": "payment",
    "status": "settled",
    "amount": "49.80",
    "currency": "EUR"
  },
  "legs": [
    { "id": "leg-1", "executionId": "77777777-7777-7777-7777-777777777777", "legIndex": 0, "partyType": "merchant", "recipient": "0xMerchant...", "amount": "45.00", "currency": "EUR", "status": "settled" },
    { "id": "leg-2", "executionId": "77777777-7777-7777-7777-777777777777", "legIndex": 1, "partyType": "platform", "recipient": "0xPlatform...", "amount": "4.80", "currency": "EUR", "status": "settled" }
  ]
}
```

### `POST /v1/agent-payments/commerce/checkout/:id/card`

Authentication: bearer token required.

Create a hosted card checkout for a cart mandate. The shopper (who need not have an Aurea account) is redirected to the returned url to pay by card. Accepts a scoped merchant API key OR a tenant-admin JWT.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Checkout id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `successUrl` | url | yes | Redirect on success (up to 2048 chars) |
| `cancelUrl` | url | yes | Redirect on cancel (up to 2048 chars) |

**Responses**

`201` Created

```json
{
  "url": "https://…/c/pay/cs_live_...",
  "sessionId": "cs_live_a1b2c3..."
}
```

**Example request**

```bash
curl -X POST https://api.aureahub.com/v1/agent-payments/commerce/checkout/CHECKOUT_ID/card \
  -H "X-Aurea-Key: apk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "successUrl": "https://acme.example/ok", "cancelUrl": "https://acme.example/cancel" }'
```

## Commerce — Chat

### `POST /v1/agent-payments/chat`

Authentication: bearer token required.

Conversational shopping agent (Product A): send a shopper message and current cart, get a reply plus the resolved cart and an optional checkout handle. Accepts a scoped merchant API key (which pins the agent) OR a tenant-admin JWT.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | no | Required unless a publishable key already pins the agent |
| `message` | string | yes | Shopper message (1–2000 chars) |
| `history` | object[] | no | Prior turns (max 20) |
| `history[].role` | enum | no | user \| assistant |
| `history[].content` | string | no | Up to 4000 chars |
| `cart` | object[] | no | Current cart (max 50 items) |
| `cart[].sku` | string | no | 1–255 chars |
| `cart[].qty` | integer | no | Positive integer |

**Responses**

`200` OK

```json
{
  "reply": "Added 1x Cotton Tee. Ready to checkout?",
  "cart": { "items": [ { "sku": "TEE-001", "name": "Cotton Tee", "qty": 1, "unitPrice": "24.90" } ], "total": "24.90", "currency": "EUR" },
  "checkout": { "checkoutId": "99999999-9999-9999-9999-999999999999", "total": "24.90", "currency": "EUR" },
  "llm": true
}
```

**Example request**

```bash
curl -X POST https://api.aureahub.com/v1/agent-payments/chat \
  -H "X-Aurea-Key: apk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "message": "I want a cotton tee" }'
```

## Refunds & Disputes

### `POST /v1/agent-payments/commerce/checkout/:id/refund`

Authentication: bearer token required.

Refund a settled card checkout (full or partial). Omit amountMinor for a full refund.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Checkout id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `amountMinor` | integer | no | Refund amount in the smallest currency unit (e.g. cents). Omit for full refund. |

**Responses**

`200` OK

```json
{
  "refundId": "re_a1b2c3...",
  "status": "succeeded",
  "executionId": "77777777-7777-7777-7777-777777777777",
  "amount": "24.90",
  "currency": "EUR"
}
```

### `GET /v1/agent-payments/commerce/disputes`

Authentication: bearer token required.

List recorded refunds and disputes/chargebacks for the tenant.

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "tenantId": "22222222-2222-2222-2222-222222222222",
      "executionId": "77777777-7777-7777-7777-777777777777",
      "kind": "dispute",
      "provider": "stripe",
      "providerRef": "dp_a1b2c3...",
      "amount": "24.90",
      "currency": "EUR",
      "status": "needs_response",
      "reason": "fraudulent",
      "createdAt": "2026-06-24T10:00:00.000Z"
    }
  ]
}
```

## Authorization Webhook

### `GET /v1/agent-payments/authorization-webhook`

Authentication: bearer token required.

Get the tenant's real-time authorization webhook configuration (the external endpoint that can veto agent payments).

**Responses**

`200` OK

```json
{
  "enabled": true,
  "url": "https://risk.acme.example/authorize",
  "fallback": "reject",
  "hasSecret": true
}
```

### `PUT /v1/agent-payments/authorization-webhook`

Authentication: bearer token required.

Create or update the tenant's real-time authorization webhook used as an external veto during payment authorization.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enabled` | boolean | yes | Whether the external veto is active |
| `url` | url | no | Webhook URL (nullable; up to 2048 chars) |
| `secret` | string | no | Signing secret (nullable; up to 512 chars) |
| `fallback` | enum | no | allow \| reject — decision when the webhook is unreachable |

**Responses**

`200` OK

```json
{
  "enabled": true,
  "url": "https://risk.acme.example/authorize",
  "fallback": "reject",
  "hasSecret": true
}
```

## Outbound Webhooks

### `POST /v1/agent-payments/webhooks/endpoints`

Authentication: bearer token required.

Register an outbound webhook endpoint to receive agent-payments events.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | url | yes | Destination URL |
| `events` | string[] | no | Event types to subscribe to — agent.payment.settled \| agent.payment.denied \| agent.payment.rejected (each up to 100 chars). Omit for all events |
| `agentId` | uuid | no | Restrict deliveries to one agent |
| `secret` | string | no | Signing secret (8–255 chars) |

**Responses**

`201` Created

```json
{
  "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
  "tenantId": "22222222-2222-2222-2222-222222222222",
  "agentId": null,
  "url": "https://acme.example/hooks/aurea",
  "events": ["agent.payment.settled", "agent.payment.denied"],
  "status": "active",
  "createdAt": "2026-06-24T10:00:00.000Z",
  "updatedAt": "2026-06-24T10:00:00.000Z"
}
```

### `GET /v1/agent-payments/webhooks/endpoints`

Authentication: bearer token required.

List the tenant's registered outbound webhook endpoints.

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
      "agentId": null,
      "url": "https://acme.example/hooks/aurea",
      "events": ["agent.payment.settled"],
      "status": "active",
      "createdAt": "2026-06-24T10:00:00.000Z"
    }
  ]
}
```

### `POST /v1/agent-payments/webhooks/run`

Authentication: bearer token required.

Run one pass of the outbound webhook delivery worker (also wired as a cron). Returns delivery counters.

**Responses**

`200` OK

```json
{ "delivered": 3, "retried": 1, "dead": 0 }
```

## Utilization & Analytics

### `GET /v1/agent-payments/agents/:id/utilization`

Authentication: bearer token required.

Get an agent's spend utilization against its policy limits (used vs remaining per window).

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Responses**

`200` OK

```json
{
  "agentId": "11111111-1111-1111-1111-111111111111",
  "currency": "EUR",
  "hasPolicy": true,
  "windows": [
    { "window": "daily", "limit": "1000.00", "used": "240.00", "remaining": "760.00" },
    { "window": "velocity", "limit": 10, "used": 2, "remaining": 8 }
  ]
}
```

### `GET /v1/agent-payments/analytics/spend`

Authentication: bearer token required.

Aggregate settled and held spend per agent over an optional date range.

**Query parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | no | Restrict to one agent |
| `from` | datetime | no | ISO 8601 range start |
| `to` | datetime | no | ISO 8601 range end |

**Responses**

`200` OK

```json
{
  "data": [
    { "agentId": "11111111-1111-1111-1111-111111111111", "settled": "1240.00", "held": "0.00", "settledCount": 18 }
  ]
}
```

### `GET /v1/agent-payments/analytics/executions`

Authentication: bearer token required.

Execution counts and totals grouped by status for the tenant.

**Responses**

`200` OK

```json
{
  "data": [
    { "status": "settled", "count": 18, "amount": "1240.00" },
    { "status": "approval_required", "count": 2, "amount": "1000.00" },
    { "status": "denied", "count": 1, "amount": "0.00" }
  ]
}
```

## Delegated Credentials

### `POST /v1/agent-payments/credentials`

Authentication: bearer token required.

Issue a scoped, revocable delegated credential for an agent. The raw token is returned exactly once and cannot be retrieved again.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | yes | Agent the credential is for |
| `mandateId` | uuid | no | Mandate the credential is bound to |
| `scope` | object | no | Arbitrary JSON scope restrictions |
| `currency` | string | no | Up to 20 chars |
| `maxAmount` | decimal | no | Total spend cap (decimal string) |
| `maxUses` | integer | no | Max number of uses |
| `expiresAt` | datetime | no | ISO 8601 expiry |

**Responses**

`201` Created

```json
{
  "credential": {
    "id": "cccccccc-cccc-cccc-cccc-cccccccccccc",
    "agentId": "11111111-1111-1111-1111-111111111111",
    "tokenPrefix": "dcr_",
    "scope": {},
    "currency": "EUR",
    "maxAmount": "100.00",
    "usedAmount": "0",
    "maxUses": 5,
    "useCount": 0,
    "status": "active",
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "createdAt": "2026-06-24T10:00:00.000Z"
  },
  "token": "dcr_live_RAWTOKEN_shown_once..."
}
```

### `GET /v1/agent-payments/credentials`

Authentication: bearer token required.

List delegated credentials, optionally filtered by agent.

**Query parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | uuid | no | Restrict to one agent |

**Responses**

`200` OK

```json
{
  "data": [
    {
      "id": "cccccccc-cccc-cccc-cccc-cccccccccccc",
      "agentId": "11111111-1111-1111-1111-111111111111",
      "tokenPrefix": "dcr_",
      "currency": "EUR",
      "maxAmount": "100.00",
      "usedAmount": "20.00",
      "maxUses": 5,
      "useCount": 1,
      "status": "active",
      "createdAt": "2026-06-24T10:00:00.000Z"
    }
  ]
}
```

### `POST /v1/agent-payments/credentials/:id/revoke`

Authentication: bearer token required.

Revoke a delegated credential immediately. Optionally record a reason.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Credential id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | no | Optional revocation reason (up to 500 chars) |

**Responses**

`200` OK

```json
{
  "id": "cccccccc-cccc-cccc-cccc-cccccccccccc",
  "status": "revoked",
  "revokedReason": "rotated",
  "revokedAt": "2026-06-24T11:00:00.000Z"
}
```

## Know-Your-Agent

### `POST /v1/agent-payments/agents/:id/kya/verify`

Authentication: bearer token required.

Submit a Know-Your-Agent verification for an agent (attestation method + trust level).

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `method` | enum | yes | self_signed \| jwt_attestation \| fido \| manual |
| `attestation` | object | no | Method-specific attestation payload |
| `trustLevel` | enum | no | none \| basic \| attested \| certified |

**Responses**

`200` OK

```json
{
  "id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "method": "jwt_attestation",
  "status": "verified",
  "trustLevel": "attested",
  "attestation": {},
  "reputationScore": 0,
  "verifiedAt": "2026-06-24T10:00:00.000Z",
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

### `GET /v1/agent-payments/agents/:id/kya`

Authentication: bearer token required.

Get the current Know-Your-Agent record for an agent. Returns { status: "none" } when no record exists.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes | Agent id |

**Responses**

`200` Record

```json
{
  "id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
  "agentId": "11111111-1111-1111-1111-111111111111",
  "method": "jwt_attestation",
  "status": "verified",
  "trustLevel": "attested",
  "reputationScore": 0,
  "createdAt": "2026-06-24T10:00:00.000Z"
}
```

`200` None

```json
{ "status": "none" }
```

## MCP

### `GET /v1/agent-payments/mcp/tools`

Authentication: bearer token required.

List the Aurea MCP tool surface — agent-payments capabilities exposed as discoverable, schema-described LLM tools.

**Responses**

`200` OK

```json
{
  "tools": [
    {
      "name": "create_checkout",
      "description": "Create a checkout session from cart items.",
      "inputSchema": { "type": "object", "properties": { "agentId": { "type": "string" } } }
    }
  ]
}
```

### `GET /v1/agent-payments/mcp/tools/:name`

Authentication: bearer token required.

Get a single MCP tool descriptor by name.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | MCP tool name |

**Responses**

`200` OK

```json
{
  "name": "create_checkout",
  "description": "Create a checkout session from cart items.",
  "inputSchema": { "type": "object", "properties": { "agentId": { "type": "string" } } }
}
```

`404` Not Found

```json
{ "detail": "Unknown MCP tool" }
```

### `POST /v1/agent-payments/mcp/call`

Authentication: bearer token required.

Invoke an MCP tool by name with a validated input payload. Runs in the caller's tenant + user context.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tool` | string | yes | MCP tool name (1–100 chars) |
| `input` | object | no | Tool input arguments |
| `rsaPublicKey` | string | no | Optional RSA public key for tools that encrypt their result |

**Responses**

`200` OK

```json
{ "result": { "checkoutId": "99999999-9999-9999-9999-999999999999", "total": "24.90", "currency": "EUR" } }
```

## Scheduler

### `POST /v1/agent-payments/recurring/run`

Authentication: bearer token required.

Manually trigger the recurring-mandate scheduler for the tenant (also runs as a cron). Fires due recurring/standing mandates as agent payments. Returns run counters.

**Responses**

`200` OK

```json
{ "fired": 2, "completed": 2, "skipped": 0 }
```

## Tenant Settings

### `GET /v1/agent-payments/tenant-settings`

Authentication: bearer token required.

Get per-tenant agent-payments enablement. A tenant is live only when both the global feature flag and this per-tenant flag are on.

**Responses**

`200` OK

```json
{ "agentPaymentsEnabled": true }
```

### `PATCH /v1/agent-payments/tenant-settings`

Authentication: bearer token required.

Enable or disable agent payments for the tenant.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enabled` | boolean | yes | Turn agent payments on/off for the tenant |

**Responses**

`200` OK

```json
{ "agentPaymentsEnabled": false }
```

## Status & Diagnostics

### `GET /v1/agent-payments/status`

Authentication: bearer token required.

Module + LLM configuration status (phase, feature-flag state, configured LLM provider, whether the LLM is configured). Read-only.

**Responses**

`200` OK

```json
{
  "module": "agent-payments",
  "phase": 1,
  "enabled": true,
  "llmProvider": "azure-openai",
  "llmConfigured": true
}
```

### `POST /v1/agent-payments/llm/ping`

Authentication: bearer token required.

Probe the agent LLM brain. Returns the provider, whether it answered, and the reply (or an error).

**Responses**

`200` OK

```json
{ "provider": "azure-openai", "ok": true, "reply": "pong" }
```

`200` Failed

```json
{ "provider": "azure-openai", "ok": false, "error": "request timed out" }
```

---

Web version: https://docs.aureahub.com/#agentic-api
