# B2B2X Public API

OpenAPI-first public contract for tenant-facing B2B2X API surfaces. Terminology and resource semantics are sourced from b2b2x-mono.

## Servers

- **Sandbox**: `https://b2b2x-sandbox.youhodler.com/api`
- **Production**: `https://b2b2x-sandbox.youhodler.com/api`

## Auth

### POST /oauth/token

**Issue access token**

Issues a bearer access token for a service principal using `client_credentials`, or a federated human access token via `urn:ietf:params:oauth:grant-type:token-exchange`. The `password` grant is rejected — human flows go through an external IdP plus token exchange.

**Request body** (`application/json`):

- `actor_token` `string`
- `client_id` `string`
- `client_secret` `string`
- `grant_type` `string`
- `requested_token_type` `string`
- `subject_token` `string`
- `subject_token_type` `string`

**Request example:**

```json
{
  "client_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "client_secret": "cs_live_abc123placeholder",
  "grant_type": "client_credentials"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJiOGUyZjFhMCJ9.sig",
    "expires_in": 3600,
    "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
    "token_type": "Bearer"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request is invalid."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Me

### GET /me/capabilities

**Get current capabilities**

Returns the raw RBAC projection of the current token: flat capability list and per-grant scope/propagation tuples. Source is the request context populated by AuthGuard.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "capabilities": [
      "withdrawals.create",
      "deposits.read",
      "clients.read"
    ],
    "context": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "scope_grants": [
      {
        "anchor_kind": "explicit",
        "capabilities": [
          "withdrawals.create",
          "deposits.read"
        ],
        "propagation": "subtree",
        "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    ],
    "subject": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "subject_kind": "user"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /me/navigation

**Get navigation sections**

Returns UI-friendly section visibility based on the caller's capabilities. The frontend uses this to build the sidebar without embedding an RBAC matrix. Optional `?scope=` narrows the context to a specific topology node.

**Parameters:**

- `scope` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "context": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "sections": [
      {
        "section": "wallet_balances",
        "visibility": "enabled"
      },
      {
        "section": "treasury",
        "visibility": "enabled"
      },
      {
        "section": "transactions",
        "visibility": "read_only"
      },
      {
        "section": "end_clients",
        "visibility": "hidden"
      },
      {
        "section": "access_control",
        "visibility": "hidden"
      },
      {
        "section": "integrations",
        "visibility": "hidden"
      }
    ],
    "subject": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "scope must be a valid TopologyRef (e.g. enterprises/<uuid>)"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "scope_not_covered"
    },
    "message": "requested navigation scope is outside granted authority"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Enterprises

### GET /enterprises

**List enterprises**

Lists enterprises visible to the caller. Requires a `platform-operators/*` topology binding — enterprise-bound tokens receive `403 forbidden_capability_scope` even if they hold the `enterprises.list` capability.

**Required capability:** `enterprises.list`

**Parameters:**

- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `admission_state` `string` (query)
- `restriction_state` `string` (query)
- `jurisdiction` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "admission_state": "operational",
        "created_at": "2026-05-01T10:00:00Z",
        "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "etag": "W/\"a1b2c3d4\"",
        "external_id": "ent-ext-0001",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "jurisdiction": "DE",
        "legal_name": "Acme Fintech GmbH",
        "metadata": {
          "hq_country": "DE",
          "industry": "fintech"
        },
        "resource": "enterprise",
        "restriction_state": "none",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /enterprises

**Admit enterprise**

Create the enterprise perimeter when it does not exist yet. Requires a `platform-operators/*` topology binding — enterprise-bound tokens receive `403 forbidden_capability_scope` even if they hold the `enterprises.create` capability.

**Required capability:** `enterprises.create`

**Request body** (`application/json`):

- `designated_admin` `object` *(required)*
  - `display_name` `string`
  - `email` `string` *(required)*
- `external_id` `string`
- `jurisdiction` `string` *(required)*
- `legal_name` `string` *(required)*
- `metadata` `object`

**Request example:**

```json
{
  "designated_admin": {
    "display_name": "Acme Admin",
    "email": "admin@acme.example"
  },
  "external_id": "ent-ext-0001",
  "jurisdiction": "DE",
  "legal_name": "Acme Fintech GmbH",
  "metadata": {
    "industry": "fintech"
  }
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "enterprise": {
      "admission_state": "operational",
      "created_at": "2026-05-01T10:00:00Z",
      "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "etag": "W/\"a1b2c3d4\"",
      "external_id": "ent-ext-0001",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "jurisdiction": "DE",
      "legal_name": "Acme Fintech GmbH",
      "metadata": {
        "hq_country": "DE",
        "industry": "fintech"
      },
      "resource": "enterprise",
      "restriction_state": "none",
      "updated_at": "2026-05-01T10:00:00Z"
    },
    "master_account": {
      "created_at": "2026-05-01T10:00:00Z",
      "display_name": "Primary Settlement Account",
      "etag": "W/\"b2c3d4e5\"",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "parent": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "resource": "master_account",
      "status": "active",
      "tenant_type": "enterprise",
      "updated_at": "2026-05-01T10:00:00Z"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /enterprises/{enterprise_id}

**Get enterprise**

**Required capability:** `enterprises.read`

**Parameters:**

- `enterprise_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "admission_state": "operational",
    "created_at": "2026-05-01T10:00:00Z",
    "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ent-ext-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "jurisdiction": "DE",
    "legal_name": "Acme Fintech GmbH",
    "metadata": {
      "hq_country": "DE",
      "industry": "fintech"
    },
    "resource": "enterprise",
    "restriction_state": "none",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /enterprises/{enterprise_id}/close

**Close enterprise**

Permanently terminates the enterprise perimeter. Returns the updated enterprise resource.

**Required capability:** `enterprises.terminate`

**Parameters:**

- `enterprise_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "admission_state": "operational",
    "created_at": "2026-05-01T10:00:00Z",
    "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ent-ext-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "jurisdiction": "DE",
    "legal_name": "Acme Fintech GmbH",
    "metadata": {
      "hq_country": "DE",
      "industry": "fintech"
    },
    "resource": "enterprise",
    "restriction_state": "none",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /enterprises/{enterprise_id}/reactivate

**Reactivate enterprise**

**Required capability:** `enterprises.reactivate`

**Parameters:**

- `enterprise_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "admission_state": "operational",
    "created_at": "2026-05-01T10:00:00Z",
    "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ent-ext-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "jurisdiction": "DE",
    "legal_name": "Acme Fintech GmbH",
    "metadata": {
      "hq_country": "DE",
      "industry": "fintech"
    },
    "resource": "enterprise",
    "restriction_state": "none",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /enterprises/{enterprise_id}/suspend

**Suspend enterprise**

**Required capability:** `enterprises.restrict`

**Parameters:**

- `enterprise_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "admission_state": "operational",
    "created_at": "2026-05-01T10:00:00Z",
    "default_master_account": "master-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ent-ext-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "jurisdiction": "DE",
    "legal_name": "Acme Fintech GmbH",
    "metadata": {
      "hq_country": "DE",
      "industry": "fintech"
    },
    "resource": "enterprise",
    "restriction_state": "none",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability or scope for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Master Accounts

### GET /master-accounts

**List master accounts**

List master accounts for a tenant scope. `scope_ref=enterprises/{id}` or `scope_ref=platform-operators/{id}`.

**Required capability:** `accounts.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "display_name": "Primary Settlement Account",
        "etag": "W/\"a1b2c3d4\"",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "master_account",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "tenant_type": "enterprise",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Retry after the specified delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "A downstream dependency is temporarily unavailable."
  }
  ```

### GET /master-accounts/{master_account_id}

**Get master account**

**Required capability:** `accounts.read`

**Parameters:**

- `master_account_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Primary Settlement Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "master_account",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "tenant_type": "enterprise",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Retry after the specified delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "A downstream dependency is temporarily unavailable."
  }
  ```

## Commercial Agreements

### GET /enterprise-commercial-agreements

**List commercial agreement versions**

**Required capability:** `commercial_agreements.read`

**Parameters:**

- `enterprise_ref` `string` (query) *(required)*
- `client_scope` `string` (query)
- `client_ref` `string` (query)
- `service_type` `string` (query)
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "page": {
      "items": [
        {
          "client_scope": {
            "kind": "all_clients"
          },
          "created_at": "2026-05-01T10:00:00Z",
          "effective_from": "2026-05-01T10:00:00Z",
          "effective_to": null,
          "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "metadata": null,
          "service_bindings": [],
          "status": "active",
          "version": 1
        }
      ],
      "next_page_token": null
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "dependency_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /enterprise-commercial-agreements

**Create commercial agreement version**

**Required capability:** `commercial_agreements.create`

**Request body** (`application/json`):

- `client_scope` `object` *(required)*
  - `kind` `string` *(required)*
- `effective_from` `string` *(required)*
- `enterprise_ref` `string` *(required)*
- `metadata` `object`
- `service_bindings` `array` *(required)*
  - `fee_schedule` `object` *(required)*
    - `minimum` `object`
      - `amount` `string` *(required)*
      - `currency` `string` *(required)*
    - `maximum` `object`
      - `amount` `string` *(required)*
      - `currency` `string` *(required)*
    - `bps` `integer`
    - `fixed` `object`
      - `amount` `string` *(required)*
      - `currency` `string` *(required)*
    - `metadata` `object`
    - `model` `string` *(required)*
    - `rounding_mode` `string`
    - `tiers` `array`
      - `bps` `integer`
      - `fixed` `object`
        - `amount` `string` *(required)*
        - `currency` `string` *(required)*
      - `up_to_amount` `string` *(required)*
  - `service_type` `string` *(required)*

**Request example:**

```json
{
  "client_scope": {
    "kind": "all_clients"
  },
  "effective_from": "2026-05-01T10:00:00Z",
  "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "metadata": null,
  "service_bindings": [
    {
      "fee_schedule": {
        "fixed": {
          "amount": "1.00",
          "currency": "USDC"
        },
        "model": "fixed"
      },
      "service_type": "conversion"
    }
  ]
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "agreement": {
      "client_scope": {
        "kind": "all_clients"
      },
      "created_at": "2026-05-01T10:00:00Z",
      "effective_from": "2026-05-01T10:00:00Z",
      "effective_to": null,
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "metadata": null,
      "service_bindings": [],
      "status": "active",
      "version": 1
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "effective_from_not_monotonic"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "reserved"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "dependency_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### GET /enterprise-commercial-agreements/{agreement_id}

**Get commercial agreement version**

**Required capability:** `commercial_agreements.read`

**Parameters:**

- `agreement_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "agreement": {
      "client_scope": {
        "kind": "all_clients"
      },
      "created_at": "2026-05-01T10:00:00Z",
      "effective_from": "2026-05-01T10:00:00Z",
      "effective_to": null,
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "metadata": null,
      "service_bindings": [],
      "status": "active",
      "version": 1
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "no_active_platform_agreement"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "dependency_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /enterprise-commercial-agreements/{agreement_id}/supersede

**Supersede commercial agreement version**

**Required capability:** `commercial_agreements.manage`

**Parameters:**

- `agreement_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `effective_to` `string` *(required)*

**Request example:**

```json
{
  "effective_to": "2026-05-01T10:00:00Z"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "agreement": {
      "client_scope": {
        "kind": "all_clients"
      },
      "created_at": "2026-05-01T10:00:00Z",
      "effective_from": "2026-05-01T10:00:00Z",
      "effective_to": null,
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "metadata": null,
      "service_bindings": [],
      "status": "active",
      "version": 1
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "effective_from_not_monotonic"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "no_active_platform_agreement"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "reserved"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "dependency_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

## Clients

### GET /clients

**List clients**

List tenant clients under an enterprise scope.

**Required capability:** `clients.read`

**Parameters:**

- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `external_id` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "display_name": "Acme Corp",
        "etag": "W/\"a1b2c3d4\"",
        "external_id": "ext-client-0042",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "metadata": {
          "crm_id": "CRM-001",
          "tier": "premium"
        },
        "resource": "client",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /clients

**Create client**

Create a client under an enterprise. The mono contract provisions the first default client account atomically.

**Required capability:** `clients.create`

**Request body** (`application/json`):

- `display_name` `string`
- `external_id` `string`
- `metadata` `object`
- `scope_ref` `string` *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.

**Request example:**

```json
{
  "display_name": "Acme Corp",
  "external_id": "ext-client-0042",
  "metadata": {
    "crm_id": "CRM-001",
    "tier": "premium"
  },
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### GET /clients/{client_id}

**Get client**

**Required capability:** `clients.read`

**Parameters:**

- `client_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### PATCH /clients/{client_id}

**Update client**

Patch tenant client. Requires `If-Match` for optimistic concurrency.

**Required capability:** `clients.manage`

**Parameters:**

- `client_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `display_name` `string`
- `external_id` `string`
- `metadata` `object`

**Request example:**

```json
{
  "display_name": "Acme Corp Updated",
  "metadata": {
    "crm_id": "CRM-002"
  }
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "Precondition failed."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /clients/{client_id}/close

**Close client**

**Required capability:** `clients.manage`

**Parameters:**

- `client_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /clients/{client_id}/reactivate

**Reactivate client**

**Required capability:** `clients.manage`

**Parameters:**

- `client_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /clients/{client_id}/suspend

**Suspend client**

**Required capability:** `clients.manage`

**Parameters:**

- `client_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "default_client_account": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "display_name": "Acme Corp",
    "etag": "W/\"a1b2c3d4\"",
    "external_id": "ext-client-0042",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": {
      "crm_id": "CRM-001",
      "tier": "premium"
    },
    "resource": "client",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "enterprise_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

## Client Accounts

### GET /client-accounts

**List client accounts**

List financial operating accounts attached to a client. The `scope_ref` query parameter is required and accepts a `clients/{uuid}` resource ref.

**Required capability:** `accounts.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "display_name": "Operating Account",
        "etag": "W/\"a1b2c3d4\"",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "client_account",
        "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /client-accounts

**Create client account**

**Required capability:** `accounts.create`

**Request body** (`application/json`):

- `display_name` `string`
- `metadata` `object`
- `scope_ref` `string` *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.

**Request example:**

```json
{
  "display_name": "Operating Account EUR",
  "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Operating Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "client_account",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /client-accounts/{client_account_id}

**Get client account**

**Required capability:** `accounts.read`

**Parameters:**

- `client_account_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Operating Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "client_account",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "client_account_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /client-accounts/{client_account_id}/close

**Close client account**

**Required capability:** `accounts.manage`

**Parameters:**

- `client_account_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Operating Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "client_account",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "client_account_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /client-accounts/{client_account_id}/reactivate

**Reactivate client account**

**Required capability:** `accounts.manage`

**Parameters:**

- `client_account_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Operating Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "client_account",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "client_account_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /client-accounts/{client_account_id}/suspend

**Suspend client account**

**Required capability:** `accounts.manage`

**Parameters:**

- `client_account_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Operating Account",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "client_account",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "Request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "client_account_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_rbac_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Users

### GET /users

**List users**

Returns a paginated list of human actors (users) within the given perimeter.

**`scope_ref` — where to find it**

Decode your bearer token (JWT). The `b2b2x:tenant_ref` claim contains the
topology reference to use as `scope_ref`:

```json
{
  "b2b2x:tenant_ref": "enterprises/c78778b9-b517-4c7b-8393-9db034ab5708"
}
```

Pass this value verbatim as the `scope_ref` query parameter. The format is
`enterprises/<uuid>` for enterprise-scoped callers or `clients/<uuid>` for
client-scoped callers.

**Required capability:** `users.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `identity_source` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "display_name": "Jane Doe",
        "email": "jane.doe@acme.example",
        "etag": "W/\"a1b2c3d4\"",
        "federation": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "identity_source": "platform-managed",
        "resource": "human_actor",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /users

**Create user**

**Required capability:** `users.create`

**Request body** (`application/json`):

- `display_name` `string`
- `email` `string` *(required)*
- `scope_ref` `string` *(required)*

**Request example:**

```json
{
  "display_name": "Jane Doe",
  "email": "jane.doe@acme.example",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The request was rejected by admissibility policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### GET /users/{user_id}

**Get user**

**Required capability:** `users.read`

**Parameters:**

- `user_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "human_actor_not_found"
    },
    "message": "The requested user does not exist"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### PATCH /users/{user_id}

**Update user**

Patch a user. Requires `If-Match`.

**Required capability:** `users.manage`

**Parameters:**

- `user_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `display_name` `string`
- `email` `string`

**Request example:**

```json
{
  "display_name": "Jane Doe Updated",
  "email": "jane.new@acme.example"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "human_actor_not_found"
    },
    "message": "The requested user does not exist"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match value does not match the current ETag"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The request was rejected by admissibility policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /users/{user_id}/deactivate

**Deactivate user**

**Required capability:** `users.manage`

**Parameters:**

- `user_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "human_actor_not_found"
    },
    "message": "The requested user does not exist"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The request was rejected by admissibility policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /users/{user_id}/reactivate

**Reactivate user**

**Required capability:** `users.manage`

**Parameters:**

- `user_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "human_actor_not_found"
    },
    "message": "The requested user does not exist"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The request was rejected by admissibility policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /users/{user_id}/suspend

**Suspend user**

**Required capability:** `users.manage`

**Parameters:**

- `user_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "display_name": "Jane Doe",
    "email": "jane.doe@acme.example",
    "etag": "W/\"a1b2c3d4\"",
    "federation": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "identity_source": "platform-managed",
    "resource": "human_actor",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The caller lacks the required capability for this scope"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "human_actor_not_found"
    },
    "message": "The requested user does not exist"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The request was rejected by admissibility policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

## Service Accounts

### GET /service-accounts

**List service accounts**

**Required capability:** `service_accounts.read`

**Parameters:**

- `parent_ref` `string` (query) *(required)*
- `status` `array` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "description": "Withdrawal automation account",
        "created_at": "2026-05-01T10:00:00Z",
        "current_secret_expires_at": "2026-05-01T10:00:00Z",
        "etag": "W/\"sa-etag-0001\"",
        "external_id": "sa-ext-001",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "previous_secret_expires_at": null,
        "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "service_account",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### POST /service-accounts

**Create service account**

Creates a service account and mints a fresh `client_secret`. The plaintext secret is returned **exactly once** in this response and is never re-fetchable afterwards — store it immediately on the client side. Use `service_accounts.rotate_secret` to issue a new secret if it is lost. The service account itself never expires on a timer; lifecycle is status-only (`active` or `revoked`). `client_secret_expires_at` is the client-secret TTL, while JWT access-token TTL is separate.

**Required capability:** `service_accounts.create`

**Request body** (`application/json`):

- `description` `string`
- `client_secret_ttl_seconds` `integer` — Optional lifetime, in seconds, for the minted `client_secret`. When omitted, the service default (`IDENTITY_ONE_TIME_SECRET_TTL_SECONDS`) applies. Minimum 60 seconds (1 minute), no upper bound. Does not affect the service account itself (no timer) or the JWT access-token TTL.
- `external_id` `string`
- `parent_ref` `string` *(required)*

**Request example:**

```json
{
  "description": "Withdrawal automation account",
  "external_id": "sa-ext-001",
  "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "client_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "client_secret": "cs_live_abc123placeholder",
    "client_secret_expires_at": "2026-05-01T10:00:00Z",
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "service_account": {
      "description": "Withdrawal automation account",
      "created_at": "2026-05-01T10:00:00Z",
      "current_secret_expires_at": "2026-05-01T10:00:00Z",
      "etag": "W/\"sa-etag-0001\"",
      "external_id": "sa-ext-001",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "previous_secret_expires_at": null,
      "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "resource": "service_account",
      "status": "active",
      "updated_at": "2026-05-01T10:00:00Z"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request validation failed"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key already used with a different payload"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is semantically invalid under current policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### GET /service-accounts/{service_account_id}

**Get service account**

**Required capability:** `service_accounts.read`

**Parameters:**

- `service_account_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "description": "Withdrawal automation account",
    "created_at": "2026-05-01T10:00:00Z",
    "current_secret_expires_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"sa-etag-0001\"",
    "external_id": "sa-ext-001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "previous_secret_expires_at": null,
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "service_account",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "service_principal_not_found"
    },
    "message": "Service account not found"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### PATCH /service-accounts/{service_account_id}

**Update service account**

Patch a service account. Requires `If-Match`.

**Required capability:** `service_accounts.manage`

**Parameters:**

- `service_account_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `description` `string`
- `external_id` `string`

**Request example:**

```json
{
  "description": "Updated description"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "description": "Withdrawal automation account",
    "created_at": "2026-05-01T10:00:00Z",
    "current_secret_expires_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"sa-etag-0001\"",
    "external_id": "sa-ext-001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "previous_secret_expires_at": null,
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "service_account",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request validation failed"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "service_principal_not_found"
    },
    "message": "Service account not found"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key already used with a different payload"
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match value does not match the current resource version"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is semantically invalid under current policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### POST /service-accounts/{service_account_id}/revoke

**Revoke service account**

**Required capability:** `service_accounts.manage`

**Parameters:**

- `service_account_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "description": "Withdrawal automation account",
    "created_at": "2026-05-01T10:00:00Z",
    "current_secret_expires_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"sa-etag-0001\"",
    "external_id": "sa-ext-001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "previous_secret_expires_at": null,
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "service_account",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request validation failed"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "service_principal_not_found"
    },
    "message": "Service account not found"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key already used with a different payload"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is semantically invalid under current policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### POST /service-accounts/{service_account_id}/rotate-secret

**Rotate service account secret**

Issues a new `client_secret`. The plaintext secret is returned **exactly once** in this response and is never re-fetchable afterwards. By default the previous secret is invalidated immediately; pass `invalidate_previous_secret: false` to keep it valid for a grace period so callers can hot-swap. The service account itself never expires on a timer; lifecycle is status-only (`active` or `revoked`). `client_secret_expires_at` is the new client-secret TTL, while JWT access-token TTL is separate.

**Required capability:** `service_accounts.rotate_secret`

**Parameters:**

- `service_account_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `client_secret_ttl_seconds` `integer` — Optional lifetime, in seconds, for the minted `client_secret`. When omitted, the service default (`IDENTITY_ONE_TIME_SECRET_TTL_SECONDS`) applies. Minimum 60 seconds (1 minute), no upper bound. Does not affect the service account itself (no timer) or the JWT access-token TTL.
- `invalidate_previous_secret` `boolean`
- `reason` `string`

**Request example:**

```json
{
  "invalidate_previous_secret": true,
  "reason": "Routine rotation"
}
```

**Responses:**

- `200` — Resource created successfully.

  ```json
  {
    "client_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "client_secret": "cs_live_abc123placeholder",
    "client_secret_expires_at": "2026-05-01T10:00:00Z",
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "service_account": {
      "description": "Withdrawal automation account",
      "created_at": "2026-05-01T10:00:00Z",
      "current_secret_expires_at": "2026-05-01T10:00:00Z",
      "etag": "W/\"sa-etag-0001\"",
      "external_id": "sa-ext-001",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "previous_secret_expires_at": null,
      "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "resource": "service_account",
      "status": "active",
      "updated_at": "2026-05-01T10:00:00Z"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request validation failed"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "service_principal_not_found"
    },
    "message": "Service account not found"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key already used with a different payload"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is semantically invalid under current policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

### POST /service-accounts/provision

**Provision service account with roles**

Creates a service account and grants it the supplied roles in a single call. Equivalent to `POST /service-accounts` followed by N × `POST /role-assignments`, but saves the client the round-trips. Best-effort grant phase: the service account is always created if `identity-service` accepts it; per-role grant failures are reported in `role_assignment_errors` (preserving the input order) and the response is still `201`. The plaintext `client_secret` is returned **exactly once** — store it before retrying any failed grants.

**Required capability:** `service_accounts.create`, `role_assignments.create`

**Request body** (`application/json`):

- `description` `string`
- `client_secret_ttl_seconds` `integer` — Optional lifetime, in seconds, for the minted `client_secret`. When omitted, the service default (`IDENTITY_ONE_TIME_SECRET_TTL_SECONDS`) applies. Minimum 60 seconds (1 minute), no upper bound. Does not affect the service account itself (no timer) or the JWT access-token TTL.
- `external_id` `string`
- `parent_ref` `string` *(required)*
- `roles` `array` *(required)*
  - `role_ref` `string` *(required)*
  - `scope_anchor_kind` `string`
  - `scope_propagation` `string`
  - `scope_ref` `string` *(required)*

**Request example:**

```json
{
  "description": "Withdrawal automation account",
  "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "roles": [
    {
      "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    }
  ]
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "client_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "client_secret": "cs_live_abc123placeholder",
    "client_secret_expires_at": "2026-05-01T10:00:00Z",
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "role_assignment_errors": [],
    "role_assignments": [],
    "service_account": {
      "description": "Withdrawal automation account",
      "created_at": "2026-05-01T10:00:00Z",
      "current_secret_expires_at": "2026-05-01T10:00:00Z",
      "etag": "W/\"sa-etag-0001\"",
      "external_id": "sa-ext-001",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "previous_secret_expires_at": null,
      "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "resource": "service_account",
      "status": "active",
      "updated_at": "2026-05-01T10:00:00Z"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "Request validation failed"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "Idempotency key already used with a different payload"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is semantically invalid under current policy"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests — retry after the indicated delay"
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "Identity service is temporarily unavailable"
  }
  ```

## Roles

### GET /roles

**List roles**

**Required capability:** `roles.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "name": "Enterprise Admin",
        "description": "Full administrative access within an enterprise",
        "created_at": "2026-05-01T10:00:00Z",
        "etag": "W/\"a1b2c3d4\"",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "permissions": [
          "withdrawals.create",
          "deposits.read",
          "clients.read"
        ],
        "platform_managed": false,
        "resource": "role",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### POST /roles

**Create role**

**Required capability:** `roles.create`

**Request body** (`application/json`):

- `name` `string` *(required)*
- `description` `string`
- `permissions` `array` *(required)*
- `scope_ref` `string` *(required)*

**Request example:**

```json
{
  "name": "Enterprise Admin",
  "description": "Full administrative access within an enterprise",
  "permissions": [
    "withdrawals.create",
    "deposits.read",
    "clients.read"
  ],
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "name": "Enterprise Admin",
    "description": "Full administrative access within an enterprise",
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "permissions": [
      "withdrawals.create",
      "deposits.read",
      "clients.read"
    ],
    "platform_managed": false,
    "resource": "role",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "request_payload_mismatch"
    },
    "message": "An earlier request used this idempotency key with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### GET /roles/{role_id}

**Get role**

**Required capability:** `roles.read`

**Parameters:**

- `role_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Enterprise Admin",
    "description": "Full administrative access within an enterprise",
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "permissions": [
      "withdrawals.create",
      "deposits.read",
      "clients.read"
    ],
    "platform_managed": false,
    "resource": "role",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "role_not_found"
    },
    "message": "The requested role was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### PATCH /roles/{role_id}

**Update role**

Patch a role. Requires `If-Match`.

**Required capability:** `roles.manage`

**Parameters:**

- `role_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `name` `string`
- `description` `string`
- `permissions` `array`

**Request example:**

```json
{
  "name": "Updated Role Name",
  "description": "Updated description",
  "permissions": [
    "withdrawals.create"
  ]
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Enterprise Admin",
    "description": "Full administrative access within an enterprise",
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "permissions": [
      "withdrawals.create",
      "deposits.read",
      "clients.read"
    ],
    "platform_managed": false,
    "resource": "role",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "role_not_found"
    },
    "message": "The requested role was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "request_payload_mismatch"
    },
    "message": "An earlier request used this idempotency key with a different payload."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match value does not match the current resource version."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### POST /roles/{role_id}/retire

**Retire role**

**Required capability:** `roles.manage`

**Parameters:**

- `role_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "name": "Enterprise Admin",
    "description": "Full administrative access within an enterprise",
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "permissions": [
      "withdrawals.create",
      "deposits.read",
      "clients.read"
    ],
    "platform_managed": false,
    "resource": "role",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "role_not_found"
    },
    "message": "The requested role was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "request_payload_mismatch"
    },
    "message": "An earlier request used this idempotency key with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

## Role Assignments

### GET /role-assignments

**List role assignments**

**Required capability:** `role_assignments.read`

**Parameters:**

- `principal_ref` `string` (query)
- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `role_ref` `string` (query)
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "etag": "W/\"a1b2c3d4\"",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "role_assignment",
        "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "scope_anchor_kind": "explicit",
        "scope_propagation": "subtree",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### POST /role-assignments

**Grant role assignment**

**Required capability:** `role_assignments.create`

**Request body** (`application/json`):

- `principal_ref` `string` *(required)*
- `role_ref` `string` *(required)*
- `scope_anchor_kind` `string`
- `scope_propagation` `string`
- `scope_ref` `string` *(required)*

**Request example:**

```json
{
  "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "scope_anchor_kind": "explicit",
  "scope_propagation": "subtree",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "role_assignment",
    "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "scope_anchor_kind": "explicit",
    "scope_propagation": "subtree",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "request_payload_mismatch"
    },
    "message": "An earlier request used this idempotency key with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### GET /role-assignments/{role_assignment_id}

**Get role assignment**

**Required capability:** `role_assignments.read`

**Parameters:**

- `role_assignment_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "role_assignment",
    "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "scope_anchor_kind": "explicit",
    "scope_propagation": "subtree",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "role_not_found"
    },
    "message": "The requested role assignment was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

### POST /role-assignments/{role_assignment_id}/revoke

**Revoke role assignment**

**Required capability:** `role_assignments.manage`

**Parameters:**

- `role_assignment_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "role_assignment",
    "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "scope_anchor_kind": "explicit",
    "scope_propagation": "subtree",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "The principal does not have the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "role_not_found"
    },
    "message": "The requested role assignment was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "request_payload_mismatch"
    },
    "message": "An earlier request used this idempotency key with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "reason": "rate_limited",
      "retry_after_ms": 5000
    },
    "message": "Too many requests. Please retry after the indicated delay."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "idempotency_in_progress"
    },
    "message": "The service is temporarily unavailable. Please retry later."
  }
  ```

## Identity Providers

### GET /identity-providers

**List identity providers**

**Required capability:** `identity_providers.manage`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "allowed_clock_skew_seconds": 30,
        "auto_jit_provision": false,
        "claim_mapping": {
          "display_name": "name",
          "email": "email",
          "external_subject": "sub",
          "family_name": "family_name",
          "given_name": "given_name"
        },
        "client_id": "my-oidc-client-id",
        "client_secret_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "discovery_mode": "oidc_discovery",
        "etag": "W/\"a1b2c3d4\"",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "issuer_uri": "https://accounts.google.com",
        "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
        "protocol": "oidc",
        "resource": "identity_provider",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "static_jwks": null,
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Caller does not have the required capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "The service is temporarily unavailable; please retry with backoff."
  }
  ```

### POST /identity-providers

**Register identity provider**

Register a federated OIDC identity provider for an enterprise. Either `discovery_mode=oidc_discovery` plus `issuer_uri`, or `discovery_mode=static_jwks` plus `static_jwks`/`jwks_uri`.

**Required capability:** `identity_providers.manage`

**Request body** (`application/json`):

- `allowed_clock_skew_seconds` `integer`
- `auto_jit_provision` `boolean`
- `claim_mapping` `object` *(required)*
  - `display_name` `string`
  - `email` `string`
  - `external_subject` `string` *(required)*
  - `family_name` `string`
  - `given_name` `string`
- `client_id` `string` *(required)*
- `client_secret_ref` `string`
- `discovery_mode` `string` *(required)*
- `issuer_uri` `string` *(required)*
- `jwks_uri` `string`
- `protocol` `string` *(required)*
- `scope_ref` `string` *(required)*
- `static_jwks` `object`

**Request example:**

```json
{
  "allowed_clock_skew_seconds": 30,
  "auto_jit_provision": false,
  "claim_mapping": {
    "display_name": "name",
    "email": "email",
    "external_subject": "sub",
    "family_name": "family_name",
    "given_name": "given_name"
  },
  "client_id": "my-oidc-client-id",
  "client_secret_ref": null,
  "discovery_mode": "oidc_discovery",
  "issuer_uri": "https://accounts.google.com",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "protocol": "oidc",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "allowed_clock_skew_seconds": 30,
    "auto_jit_provision": false,
    "claim_mapping": {
      "display_name": "name",
      "email": "email",
      "external_subject": "sub",
      "family_name": "family_name",
      "given_name": "given_name"
    },
    "client_id": "my-oidc-client-id",
    "client_secret_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "discovery_mode": "oidc_discovery",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "issuer_uri": "https://accounts.google.com",
    "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
    "protocol": "oidc",
    "resource": "identity_provider",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "static_jwks": null,
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "capability_scope_mismatch"
    },
    "message": "The request payload is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Caller does not have the required capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "The idempotency key has already been used with different parameters."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "The service is temporarily unavailable; please retry with backoff."
  }
  ```

### GET /identity-providers/{identity_provider_id}

**Get identity provider**

**Required capability:** `identity_providers.manage`

**Parameters:**

- `identity_provider_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "allowed_clock_skew_seconds": 30,
    "auto_jit_provision": false,
    "claim_mapping": {
      "display_name": "name",
      "email": "email",
      "external_subject": "sub",
      "family_name": "family_name",
      "given_name": "given_name"
    },
    "client_id": "my-oidc-client-id",
    "client_secret_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "discovery_mode": "oidc_discovery",
    "etag": "W/\"a1b2c3d4\"",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "issuer_uri": "https://accounts.google.com",
    "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
    "protocol": "oidc",
    "resource": "identity_provider",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "static_jwks": null,
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Caller does not have the required capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "service_principal_not_found"
    },
    "message": "The requested identity provider was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "federation_discovery_failed"
    },
    "message": "The service is temporarily unavailable; please retry with backoff."
  }
  ```

## Capabilities

### GET /capabilities

**List capabilities**

Lists every capability that may be granted via roles, scoped to the given topology node.

**Required capability:** `feature_flags.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "name": "withdrawals.create",
        "enabled": true
      },
      {
        "name": "deposits.read",
        "enabled": true
      },
      {
        "name": "clients.read",
        "enabled": false
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "scope_not_covered"
    },
    "message": "Forbidden: capability scope not covered."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### PATCH /clients/{client_id}/capabilities/{capability_name}

**Toggle capability override for client (deprecated)**

Deprecated. This endpoint always returns an error. Use role-based grants via `POST /role-assignments` instead.

**Parameters:**

- `client_id` `string` (path) *(required)*
- `capability_name` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "capability": "withdrawals.create",
    "enabled": true
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `410` — This endpoint has been removed. Check the API changelog for the replacement.

  ```json
  {
    "code": "deprecated_endpoint",
    "message": "PATCH /clients/:client_id/capabilities/:capability_name is deprecated; tracked in #318"
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Policies

### GET /policy-rules

**List policy rules**

**Required capability:** `policies.read`

**Parameters:**

- `scope_ref` `string` (query) — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `operation_type` `string` (query)
- `status_filter` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "name": "Large crypto withdrawal approval",
        "description": "Require compliance review for large crypto withdrawals",
        "activated_at": "2026-05-01T10:00:00Z",
        "conditions": [
          {
            "amount_basis": "usd_equivalent",
            "kind": "amount_threshold",
            "operator": "gte",
            "threshold": {
              "currency": "USD",
              "value": "10000.00"
            }
          }
        ],
        "created_at": "2026-05-01T10:00:00Z",
        "decision": {
          "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
          "initiator_cannot_approve": true,
          "kind": "require_approval",
          "reason": "large_crypto_withdrawal",
          "threshold": 2
        },
        "etag": "policy-rule-v2-0001",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "operation_type": "withdrawal",
        "resource": "policy_rule",
        "retired_at": null,
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z",
        "version": 1
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /policy-rules

**Create policy rule**

**Required capability:** `policies.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):

- `name` `string` *(required)*
- `description` `string`
- `conditions` `array` *(required)*
- `decision` `any` *(required)*
- `idempotency_key` `string`
- `operation_type` `string` *(required)*
- `scope_ref` `string` *(required)*

**Request example:**

```json
{
  "name": "Large crypto withdrawal approval",
  "description": "Require compliance review for large crypto withdrawals",
  "conditions": [
    {
      "amount_basis": "usd_equivalent",
      "kind": "amount_threshold",
      "operator": "gte",
      "threshold": {
        "currency": "USD",
        "value": "10000.00"
      }
    }
  ],
  "decision": {
    "approver_role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "initiator_cannot_approve": true,
    "kind": "require_approval",
    "reason": "large_crypto_withdrawal",
    "threshold": 2
  },
  "operation_type": "withdrawal",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "name": "Large crypto withdrawal approval",
    "description": "Require compliance review for large crypto withdrawals",
    "activated_at": "2026-05-01T10:00:00Z",
    "conditions": [
      {
        "amount_basis": "usd_equivalent",
        "kind": "amount_threshold",
        "operator": "gte",
        "threshold": {
          "currency": "USD",
          "value": "10000.00"
        }
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "decision": {
      "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
      "initiator_cannot_approve": true,
      "kind": "require_approval",
      "reason": "large_crypto_withdrawal",
      "threshold": 2
    },
    "etag": "policy-rule-v2-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "operation_type": "withdrawal",
    "resource": "policy_rule",
    "retired_at": null,
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "version": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "validation_failed",
    "details": {
      "reason": "invalid_condition"
    },
    "message": "Policy rule is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /policy-rules/{rule_id}

**Get policy rule**

**Required capability:** `policies.read`

**Parameters:**

- `rule_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Large crypto withdrawal approval",
    "description": "Require compliance review for large crypto withdrawals",
    "activated_at": "2026-05-01T10:00:00Z",
    "conditions": [
      {
        "amount_basis": "usd_equivalent",
        "kind": "amount_threshold",
        "operator": "gte",
        "threshold": {
          "currency": "USD",
          "value": "10000.00"
        }
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "decision": {
      "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
      "initiator_cannot_approve": true,
      "kind": "require_approval",
      "reason": "large_crypto_withdrawal",
      "threshold": 2
    },
    "etag": "policy-rule-v2-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "operation_type": "withdrawal",
    "resource": "policy_rule",
    "retired_at": null,
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "version": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "policy_rule_not_found"
    },
    "message": "Policy rule not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### PATCH /policy-rules/{rule_id}

**Update policy rule**

**Required capability:** `policies.manage`

**Parameters:**

- `rule_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `name` `string`
- `description` `string`
- `conditions` `array`
- `decision` `any`
- `operation_type` `string`
- `scope_ref` `string`

**Request example:**

```json
{
  "name": "Updated policy rule name"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Large crypto withdrawal approval",
    "description": "Require compliance review for large crypto withdrawals",
    "activated_at": "2026-05-01T10:00:00Z",
    "conditions": [
      {
        "amount_basis": "usd_equivalent",
        "kind": "amount_threshold",
        "operator": "gte",
        "threshold": {
          "currency": "USD",
          "value": "10000.00"
        }
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "decision": {
      "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
      "initiator_cannot_approve": true,
      "kind": "require_approval",
      "reason": "large_crypto_withdrawal",
      "threshold": 2
    },
    "etag": "policy-rule-v2-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "operation_type": "withdrawal",
    "resource": "policy_rule",
    "retired_at": null,
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "version": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "validation_failed",
    "details": {
      "reason": "invalid_condition"
    },
    "message": "Policy rule is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "policy_rule_not_found"
    },
    "message": "Policy rule not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "conflict",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "ETag mismatch — the rule was modified by a concurrent request."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /policy-rules/{rule_id}/activate

**Activate policy rule**

**Required capability:** `policies.manage`

**Parameters:**

- `rule_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Large crypto withdrawal approval",
    "description": "Require compliance review for large crypto withdrawals",
    "activated_at": "2026-05-01T10:00:00Z",
    "conditions": [
      {
        "amount_basis": "usd_equivalent",
        "kind": "amount_threshold",
        "operator": "gte",
        "threshold": {
          "currency": "USD",
          "value": "10000.00"
        }
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "decision": {
      "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
      "initiator_cannot_approve": true,
      "kind": "require_approval",
      "reason": "large_crypto_withdrawal",
      "threshold": 2
    },
    "etag": "policy-rule-v2-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "operation_type": "withdrawal",
    "resource": "policy_rule",
    "retired_at": null,
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "version": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "validation_failed",
    "details": {
      "reason": "invalid_condition"
    },
    "message": "Policy rule is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "policy_rule_not_found"
    },
    "message": "Policy rule not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "conflict",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "ETag mismatch — the rule was modified by a concurrent request."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /policy-rules/{rule_id}/retire

**Retire policy rule**

**Required capability:** `policies.manage`

**Parameters:**

- `rule_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": "No longer needed"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "name": "Large crypto withdrawal approval",
    "description": "Require compliance review for large crypto withdrawals",
    "activated_at": "2026-05-01T10:00:00Z",
    "conditions": [
      {
        "amount_basis": "usd_equivalent",
        "kind": "amount_threshold",
        "operator": "gte",
        "threshold": {
          "currency": "USD",
          "value": "10000.00"
        }
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "decision": {
      "approver_role_ref": "roles/44444444-4444-4444-8444-444444444444",
      "initiator_cannot_approve": true,
      "kind": "require_approval",
      "reason": "large_crypto_withdrawal",
      "threshold": 2
    },
    "etag": "policy-rule-v2-0001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "operation_type": "withdrawal",
    "resource": "policy_rule",
    "retired_at": null,
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "version": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "validation_failed",
    "details": {
      "reason": "invalid_condition"
    },
    "message": "Policy rule is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "policy_rule_not_found"
    },
    "message": "Policy rule not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "conflict",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "ETag mismatch — the rule was modified by a concurrent request."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Action Tokens

### POST /action-tokens

**Issue action token**

Issues a short-lived action token that authorises a specific money-movement command. The token is bound to the caller and to the command digest of the requested action. Pass it in the `X-Action-Token` header when submitting the authorised command (e.g. `POST /withdrawals`). Service principals are exempt from this requirement.

**Request body** (`application/json`):

- `action` `string` *(required)*
- `withdrawal` `object` *(required)* — Withdrawal request parameters identical to the `POST /withdrawals` body. Edge computes the command digest server-side so callers never have to implement digest logic.

**Request example:**

```json
{
  "action": "withdrawal.create",
  "withdrawal": {}
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "bound_actor": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "bound_command_digest": "sha256:abcdef1234567890",
    "expires_at": "2026-05-01T10:00:00Z",
    "token": "act_tok_abc123xyz"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "State conflict — the request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

## Approvals

### GET /approvals

**List approvals**

**Required capability:** `approvals.read`

**Parameters:**

- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `status` `string` (query)
- `operation_id` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "action_family": "withdrawal",
        "created_at": "2026-05-01T10:00:00Z",
        "decision": null,
        "expires_at": "2026-05-01T10:00:00Z",
        "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "initiated_by": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "requirement_snapshot": {
          "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "expires_at": "2026-05-01T10:00:00Z",
          "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "initiator_cannot_approve": true,
          "reason_code": "high_value",
          "required_human_approvals": 1,
          "requirement_key": "withdrawal_approval",
          "source": "policy"
        },
        "resource": "approval",
        "status": "pending",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### GET /approvals/{approval_id}

**Get approval**

**Required capability:** `approvals.read`

**Parameters:**

- `approval_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "action_family": "withdrawal",
    "created_at": "2026-05-01T10:00:00Z",
    "decision": null,
    "expires_at": "2026-05-01T10:00:00Z",
    "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "initiated_by": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requirement_snapshot": {
      "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "expires_at": "2026-05-01T10:00:00Z",
      "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "initiator_cannot_approve": true,
      "reason_code": "high_value",
      "required_human_approvals": 1,
      "requirement_key": "withdrawal_approval",
      "source": "policy"
    },
    "resource": "approval",
    "status": "pending",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### POST /approvals/{approval_id}/approve

**Approve approval**

**Required capability:** `approvals.decide`

**Parameters:**

- `approval_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "action_family": "withdrawal",
    "created_at": "2026-05-01T10:00:00Z",
    "decision": null,
    "expires_at": "2026-05-01T10:00:00Z",
    "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "initiated_by": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requirement_snapshot": {
      "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "expires_at": "2026-05-01T10:00:00Z",
      "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "initiator_cannot_approve": true,
      "reason_code": "high_value",
      "required_human_approvals": 1,
      "requirement_key": "withdrawal_approval",
      "source": "policy"
    },
    "resource": "approval",
    "status": "pending",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "State conflict — the approval is not in a state that allows this action."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### POST /approvals/{approval_id}/cancel

**Cancel approval**

**Required capability:** `approvals.decide`

**Parameters:**

- `approval_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "action_family": "withdrawal",
    "created_at": "2026-05-01T10:00:00Z",
    "decision": null,
    "expires_at": "2026-05-01T10:00:00Z",
    "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "initiated_by": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requirement_snapshot": {
      "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "expires_at": "2026-05-01T10:00:00Z",
      "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "initiator_cannot_approve": true,
      "reason_code": "high_value",
      "required_human_approvals": 1,
      "requirement_key": "withdrawal_approval",
      "source": "policy"
    },
    "resource": "approval",
    "status": "pending",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "State conflict — the approval is not in a state that allows this action."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### GET /approvals/{approval_id}/eligible-approvers

**List eligible approvers**

**Required capability:** `approvals.read`

**Parameters:**

- `approval_id` `string` (path) *(required)*
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "display_name": "Jane Smith",
        "eligibility_basis": "role_assignment",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "human_actor"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### POST /approvals/{approval_id}/reject

**Reject approval**

**Required capability:** `approvals.decide`

**Parameters:**

- `approval_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `reason` `string`

**Request example:**

```json
{
  "reason": ""
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "action_family": "withdrawal",
    "created_at": "2026-05-01T10:00:00Z",
    "decision": null,
    "expires_at": "2026-05-01T10:00:00Z",
    "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "initiated_by": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requirement_snapshot": {
      "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "expires_at": "2026-05-01T10:00:00Z",
      "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "initiator_cannot_approve": true,
      "reason_code": "high_value",
      "required_human_approvals": 1,
      "requirement_key": "withdrawal_approval",
      "source": "policy"
    },
    "resource": "approval",
    "status": "pending",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid request payload."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "State conflict — the approval is not in a state that allows this action."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

## Balances

### GET /client-accounts/{client_account_id}/balances

**Get client-account balances**

Returns balances for a client account. Pass `?asset=` to fetch a single balance; otherwise returns every asset present on the account.

**Required capability:** `accounts.read`

**Parameters:**

- `client_account_id` `string` (path) *(required)*
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "asset": "USDC",
        "available": "950.00",
        "held": "50.00",
        "overdraft_headroom": null,
        "overdraft_limit": null,
        "overdraft_used": null,
        "owner_ref": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "owner_subtype": "client_account",
        "total": "1000.00",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "original_transaction_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "ledger_db_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /master-accounts/{master_account_id}/balances

**Get master-account balances**

Returns balances for a master account. Pass `?asset=` to fetch a single balance; otherwise returns every asset present on the account.

**Required capability:** `accounts.read`

**Parameters:**

- `master_account_id` `string` (path) *(required)*
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "asset": "USDC",
        "available": "950.00",
        "held": "50.00",
        "overdraft_headroom": null,
        "overdraft_limit": null,
        "overdraft_used": null,
        "owner_ref": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "owner_subtype": "client_account",
        "total": "1000.00",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "original_transaction_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "ledger_db_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Deposits

### GET /deposits

**List deposits**

**Required capability:** `deposits.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)
- `from_date` `string` (query)
- `to_date` `string` (query)
- `asset` `string` (query)
- `min_amount` `string` (query)
- `sort` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "approval_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "deposit_instruction_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "failure_reason": null,
        "family": "deposit",
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fee_transaction_ids": [],
        "fill_rate": null,
        "funding_endpoint_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "inbound_attempt_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "principal_transaction_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail_correlation_ref": "TXN-0001",
        "settled_at": "2026-05-01T10:00:00Z",
        "settlement_ref": "SETTLE-0001",
        "status": "executed",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /deposits/{deposit_id}

**Get deposit**

**Required capability:** `deposits.read`

**Parameters:**

- `deposit_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "deposit_instruction_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "failure_reason": null,
    "family": "deposit",
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fee_transaction_ids": [],
    "fill_rate": null,
    "funding_endpoint_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "inbound_attempt_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "principal_transaction_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail_correlation_ref": "TXN-0001",
    "settled_at": "2026-05-01T10:00:00Z",
    "settlement_ref": "SETTLE-0001",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "deposit"
    },
    "message": "Deposit not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Deposit Instructions

### GET /deposit-instructions

**List deposit instructions**

Lists deposit instructions for the selected rail. Crypto instructions route to the custody rails backend; fiat instructions are delegated to `fiat-rails-service` and scoped to the supplied `account_ref`.

**Required capability:** `deposit_instructions.read`

**Parameters:**

- `account_ref` `string` (query) *(required)*
- `funding_endpoint` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `rail_class` `string` (query) *(required)*
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "asset": "USDC",
        "created_at": "2026-05-01T10:00:00Z",
        "crypto_routing": {
          "asset": "USDC",
          "endpoint": {
            "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
            "memo": null
          },
          "network": "ethereum"
        },
        "expires_at": null,
        "fiat_routing": null,
        "funding_endpoint_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail_class": "crypto",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Request parameter is invalid or missing."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated or the bearer token is invalid."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "bad_gateway",
    "message": "Upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### GET /deposit-instructions/{deposit_instruction_id}

**Get deposit instruction**

Reads a deposit instruction by id. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat reads also require `account_ref` because fiat deposit instructions are account-scoped; they are delegated to `fiat-rails-service`, and unknown or out-of-scope fiat ids return `resource_not_found`.

**Required capability:** `deposit_instructions.read`

**Parameters:**

- `deposit_instruction_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "endpoint": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "network": "ethereum"
    },
    "expires_at": null,
    "fiat_routing": null,
    "funding_endpoint_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail_class": "crypto",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Request parameter is invalid or missing."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated or the bearer token is invalid."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "bad_gateway",
    "message": "Upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

## Funding Endpoints

### GET /funding-endpoints

**List funding endpoints**

Lists deposit-side endpoints for the selected rail. Crypto endpoints route to the custody rails backend; fiat endpoints are delegated to `fiat-rails-service` and scoped to the supplied `account_ref`.

**Required capability:** `funding_endpoints.read`

**Parameters:**

- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) *(required)*
- `status` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "asset": "USDC",
        "created_at": "2026-05-01T10:00:00Z",
        "crypto_routing": {
          "asset": "USDC",
          "endpoint": {
            "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
            "memo": null
          },
          "network": "ethereum"
        },
        "fiat_rail": null,
        "fiat_routing": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "network": "ethereum",
        "rail_class": "crypto",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: rail_class"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "provider_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "The selected rail provider is currently unavailable."
  }
  ```

### POST /funding-endpoints

**Provision funding endpoint**

Provisions a new deposit-side endpoint. Crypto routes to the custody rails backend. Fiat requests carry only `account_ref` and `routing`; the pooled fiat route owner is derived server-side inside `rails-router-service` rather than supplied in the request body, and provisioning is delegated to `fiat-rails-service` after the route-guard/availability pipeline approves the route. Idempotent on the required `Idempotency-Key` header.

**Required capability:** `funding_endpoints.provision`

**Parameters:**

- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):


**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "rail_class": "crypto",
  "routing": {
    "asset": "USDC",
    "network": "ethereum"
  }
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "endpoint": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "network": "ethereum"
    },
    "fiat_rail": null,
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "network": "ethereum",
    "rail_class": "crypto",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "crypto funding endpoint routing must include only asset and network"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "idempotency_conflict"
    },
    "message": "A funding endpoint with this idempotency key already exists."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "provisioning_rejected",
    "details": {
      "reason": "not_admissible"
    },
    "message": "Funding endpoint provisioning was rejected by the rail provider."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "provider_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "The selected rail provider is currently unavailable."
  }
  ```

### GET /funding-endpoints/{funding_endpoint_id}

**Get funding endpoint**

Reads a funding endpoint by id. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat reads also require `account_ref` because fiat funding endpoints are account-scoped; they are delegated to `fiat-rails-service`, and unknown or out-of-scope fiat ids return `resource_not_found`.

**Required capability:** `funding_endpoints.read`

**Parameters:**

- `funding_endpoint_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "endpoint": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "network": "ethereum"
    },
    "fiat_rail": null,
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "network": "ethereum",
    "rail_class": "crypto",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: rail_class"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "original_transaction_not_found"
    },
    "message": "Funding endpoint not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "provider_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "The selected rail provider is currently unavailable."
  }
  ```

## Payment Methods

### GET /available-payment-methods

**List available payment methods**

Returns account-scoped deposit setup availability projected onto payment methods. Items in this response reflect the same runtime-availability verdict that funding-endpoint provisioning evaluates, so callers may rely on them as a setup-readiness signal. For the global reference catalog (which is NOT a setup guarantee), use `/payment-methods`.

**Parameters:**

- `rail` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `account_ref` `string` (query) *(required)*
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "code": "sepa_credit_transfer",
        "currencies": [
          "EUR"
        ],
        "display_name": "SEPA",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail": "sepa_credit_transfer"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: account_ref"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "account_ref requires a bound operating scope on this endpoint"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /payment-methods

**List payment methods**

Returns the global payment-method reference catalog. This is reference data, not a setup-availability guarantee — it does not consult per-account runtime availability or per-scope eligibility. Fiat payment methods currently return an empty collection while fiat rails are disabled. For account-scoped deposit setup availability, use `/available-payment-methods`.

**Parameters:**

- `rail` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "code": "sepa_credit_transfer",
        "currencies": [
          "EUR"
        ],
        "display_name": "SEPA",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail": "sepa_credit_transfer"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid query parameter"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /payment-methods

**Create payment method**

**Required capability:** `payment_methods.manage`

**Request body** (`application/json`):

- `active` `boolean`
- `code` `string` *(required)*
- `currencies` `array` *(required)*
- `display_name` `string` *(required)*
- `rail` `string` *(required)*

**Request example:**

```json
{
  "active": true,
  "code": "sepa_credit_transfer",
  "currencies": [
    "EUR"
  ],
  "display_name": "SEPA",
  "rail": "sepa_credit_transfer"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "active": true,
    "code": "sepa_credit_transfer",
    "currencies": [
      "EUR"
    ],
    "display_name": "SEPA",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail": "sepa_credit_transfer"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: code"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payment_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### PATCH /payment-methods/{payment_method_id}

**Update payment method**

**Required capability:** `payment_methods.manage`

**Parameters:**

- `payment_method_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `active` `boolean`
- `currencies` `array`
- `display_name` `string`
- `rail` `string`

**Request example:**

```json
{
  "active": false,
  "display_name": "SEPA Updated"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "active": true,
    "code": "sepa_credit_transfer",
    "currencies": [
      "EUR"
    ],
    "display_name": "SEPA",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail": "sepa_credit_transfer"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid field value"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payment_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "payment method not found"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### DELETE /payment-methods/{payment_method_id}

**Delete payment method**

**Required capability:** `payment_methods.manage`

**Parameters:**

- `payment_method_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "payment_method_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payment_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "payment method not found"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Payout Methods

### GET /eligible-payout-methods

**List eligible payout methods**

Returns scope-scoped withdrawal discovery projected onto payout methods. For the global catalog, use `/payout-methods`.

**Parameters:**

- `rail` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "code": "sepa_credit_transfer",
        "currencies": [
          "EUR"
        ],
        "display_name": "SEPA",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail": "sepa_credit_transfer"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: scope_ref"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "scope_ref requires a bound tenant scope on this endpoint"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /payout-methods

**List payout methods**

Returns the global payout-method catalog. Fiat payout methods currently return an empty collection while fiat rails are disabled. For scope-scoped withdrawal discovery, use `/eligible-payout-methods`.

**Parameters:**

- `rail` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "code": "sepa_credit_transfer",
        "currencies": [
          "EUR"
        ],
        "display_name": "SEPA",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "rail": "sepa_credit_transfer"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid query parameter"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /payout-methods

**Create payout method**

**Required capability:** `payout_methods.manage`

**Request body** (`application/json`):

- `active` `boolean`
- `code` `string` *(required)*
- `currencies` `array` *(required)*
- `display_name` `string` *(required)*
- `rail` `string` *(required)*

**Request example:**

```json
{
  "active": true,
  "code": "sepa_credit_transfer",
  "currencies": [
    "EUR"
  ],
  "display_name": "SEPA",
  "rail": "sepa_credit_transfer"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "active": true,
    "code": "sepa_credit_transfer",
    "currencies": [
      "EUR"
    ],
    "display_name": "SEPA",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail": "sepa_credit_transfer"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: code"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payout_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### PATCH /payout-methods/{payout_method_id}

**Update payout method**

**Required capability:** `payout_methods.manage`

**Parameters:**

- `payout_method_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `active` `boolean`
- `currencies` `array`
- `display_name` `string`
- `rail` `string`

**Request example:**

```json
{
  "active": false,
  "display_name": "SEPA Updated"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "active": true,
    "code": "sepa_credit_transfer",
    "currencies": [
      "EUR"
    ],
    "display_name": "SEPA",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "rail": "sepa_credit_transfer"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Invalid field value"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payout_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "payout method not found"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### DELETE /payout-methods/{payout_method_id}

**Delete payout method**

**Required capability:** `payout_methods.manage`

**Parameters:**

- `payout_method_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "payout_method_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "capability": "payout_methods.manage",
      "reason": "missing_capability"
    },
    "message": "missing capability"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "payout method not found"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Crypto Networks

### GET /available-crypto-networks

**List available crypto networks**

Returns account-scoped setup availability projected onto crypto networks. Items in this response reflect the same runtime-availability verdict that funding-endpoint provisioning evaluates, so callers may rely on them as a deposit-setup-readiness signal. `direction` defaults to deposit. For the global reference catalog (which is NOT a setup guarantee), use `/crypto-networks`; for topology-scoped eligibility, use `/eligible-crypto-networks`.

**Parameters:**

- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `direction` `string` (query)
- `account_ref` `string` (query) *(required)*
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "assets": [
          "USDC",
          "ETH"
        ],
        "code": "ethereum",
        "display_name": "Ethereum"
      },
      {
        "active": true,
        "assets": [
          "USDC",
          "MATIC"
        ],
        "code": "polygon",
        "display_name": "Polygon"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Request parameter is invalid or missing."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated or the bearer token is invalid."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "bad_gateway",
    "message": "Upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### GET /crypto-networks

**List crypto networks**

Returns the global crypto-network reference catalog. This is reference data, not a setup-availability guarantee — it does not consult per-account runtime availability or per-scope eligibility. For account-scoped deposit availability, use `/available-crypto-networks`; for topology-scoped eligibility, use `/eligible-crypto-networks`.

**Parameters:**

- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `active` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "assets": [
          "USDC",
          "ETH"
        ],
        "code": "ethereum",
        "display_name": "Ethereum"
      },
      {
        "active": true,
        "assets": [
          "USDC",
          "MATIC"
        ],
        "code": "polygon",
        "display_name": "Polygon"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Request parameter is invalid or missing."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated or the bearer token is invalid."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "bad_gateway",
    "message": "Upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

### GET /eligible-crypto-networks

**List eligible crypto networks**

Returns scope-scoped eligibility projected onto crypto networks. `direction` defaults to deposit. For account-runtime availability, use `/available-crypto-networks`; for the global catalog, use `/crypto-networks`.

**Parameters:**

- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `direction` `string` (query)
- `scope_ref` `string` (query) *(required)* — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "assets": [
          "USDC",
          "ETH"
        ],
        "code": "ethereum",
        "display_name": "Ethereum"
      },
      {
        "active": true,
        "assets": [
          "USDC",
          "MATIC"
        ],
        "code": "polygon",
        "display_name": "Polygon"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Request parameter is invalid or missing."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Caller is not authenticated or the bearer token is invalid."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "bad_gateway",
    "message": "Upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable; retry with backoff."
  }
  ```

## Conversion Pairs

### GET /conversion-pairs

**List conversion pairs**

Lists global product support corridors for conversions. Conversion pairs describe platform-supported source/target currency directions and static source amount bounds only; they are not account-specific eligibility, pricing, fee, liquidity, or execution guarantees. Use conversion preflight/preview for account-specific availability and economics.

**Parameters:**

- `source_currency` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `target_currency` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `active` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "active": true,
        "display_order": 0,
        "id": "usdc-btc",
        "max_source_amount": "100000.00",
        "min_source_amount": "10.00",
        "settlement_model": "internal_platform",
        "source_currency": "USDC",
        "target_currency": "BTC"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /conversion-pairs/{conversion_pair_id}

**Get conversion pair**

Returns one global product support corridor by catalog id. This is static platform catalog data, not account-specific eligibility or a quote.

**Parameters:**

- `conversion_pair_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "active": true,
    "display_order": 0,
    "id": "usdc-btc",
    "max_source_amount": "100000.00",
    "min_source_amount": "10.00",
    "settlement_model": "internal_platform",
    "source_currency": "USDC",
    "target_currency": "BTC"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "conversion_pair_not_found"
    },
    "message": "Conversion pair not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Webhook Subscriptions

### GET /webhook-subscriptions

**List webhook subscriptions**

Lists webhook subscriptions. If omitted, `scope_ref` is derived from the authenticated enterprise or client context.

**Required capability:** `webhooks.read`

**Parameters:**

- `scope_ref` `string` (query) — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "created_at": "2026-05-01T10:00:00Z",
        "etag": "W/\"a1b2c3d4\"",
        "event_types": [
          "operations.withdrawal.settled.v1"
        ],
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "webhook_subscription",
        "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z",
        "url": "https://example.com/webhooks"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions

**Create webhook subscription**

Creates an active webhook subscription. If omitted, `scope_ref` is derived from the authenticated enterprise or client context.

**Required capability:** `webhooks.create`

**Request body** (`application/json`):

- `event_types` `array` *(required)* — Non-empty event type filter. Use ["*"] to subscribe to all event types; otherwise provide exact catalog event types or catalog-derived group wildcards such as "operations.withdrawal.*.v1" and "operations.*.v1".
- `scope_ref` `string`
- `secret` `string` *(required)*
- `url` `string` *(required)*

**Request example:**

```json
{
  "event_types": [
    "operations.withdrawal.settled.v1"
  ],
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "secret": "wh_secret_placeholder",
  "url": "https://example.com/webhooks"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /webhook-subscriptions/{subscription_id}

**Get webhook subscription**

**Required capability:** `webhooks.read`

**Parameters:**

- `subscription_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### PATCH /webhook-subscriptions/{subscription_id}

**Update webhook subscription**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `event_types` `array` — Non-empty event type filter. Use ["*"] to subscribe to all event types; otherwise provide exact catalog event types or catalog-derived group wildcards such as "operations.withdrawal.*.v1" and "operations.*.v1".
- `status` `string`
- `url` `string`

**Request example:**

```json
{
  "status": "paused",
  "url": "https://example.com/webhooks/updated"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match header does not match the current resource version."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions/{subscription_id}/delete

**Delete webhook subscription**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match header does not match the current resource version."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /webhook-subscriptions/{subscription_id}/deliveries

**List webhook deliveries**

**Required capability:** `webhooks.read`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "attempt_count": 1,
        "attempts": [
          {
            "attempt_number": 1,
            "attempted_at": "2026-05-01T10:00:00Z",
            "delivery_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "duration_ms": 142,
            "http_status_code": 200,
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "resource": "delivery_attempt",
            "response_body": "ok"
          }
        ],
        "created_at": "2026-05-01T10:00:00Z",
        "event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "last_attempt_at": "2026-05-01T10:00:00Z",
        "next_retry_at": null,
        "resource": "webhook_delivery",
        "status": "delivered",
        "subscription_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /webhook-subscriptions/{subscription_id}/deliveries/{delivery_id}

**Get webhook delivery**

**Required capability:** `webhooks.read`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `delivery_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "attempt_count": 1,
    "attempts": [
      {
        "attempt_number": 1,
        "attempted_at": "2026-05-01T10:00:00Z",
        "delivery_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "duration_ms": 142,
        "http_status_code": 200,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource": "delivery_attempt",
        "response_body": "ok"
      }
    ],
    "created_at": "2026-05-01T10:00:00Z",
    "event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "last_attempt_at": "2026-05-01T10:00:00Z",
    "next_retry_at": null,
    "resource": "webhook_delivery",
    "status": "delivered",
    "subscription_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_delivery_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions/{subscription_id}/deliveries/{delivery_id}/redeliver

**Redeliver webhook delivery**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `delivery_id` `string` (path) *(required)*

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "accepted": true,
    "delivery_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_delivery_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions/{subscription_id}/disable

**Disable webhook subscription**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match header does not match the current resource version."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions/{subscription_id}/enable

**Enable webhook subscription**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*
- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "created_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"a1b2c3d4\"",
    "event_types": [
      "operations.withdrawal.settled.v1"
    ],
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "webhook_subscription",
    "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z",
    "url": "https://example.com/webhooks"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match header does not match the current resource version."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /webhook-subscriptions/{subscription_id}/test

**Send webhook test delivery**

**Required capability:** `webhooks.manage`

**Parameters:**

- `subscription_id` `string` (path) *(required)*

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "accepted": true,
    "delivery": {
      "attempt_count": 1,
      "attempts": [
        {
          "attempt_number": 1,
          "attempted_at": "2026-05-01T10:00:00Z",
          "delivery_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "duration_ms": 142,
          "http_status_code": 200,
          "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "resource": "delivery_attempt",
          "response_body": "ok"
        }
      ],
      "created_at": "2026-05-01T10:00:00Z",
      "event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "last_attempt_at": "2026-05-01T10:00:00Z",
      "next_retry_at": null,
      "resource": "webhook_delivery",
      "status": "delivered",
      "subscription_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "webhook_subscription_not_found"
    },
    "message": "The requested resource was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "A duplicate request was detected with a different payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Events

### GET /events

**List events**

Lists tenant-visible platform events. If omitted, `scope_ref` is derived from the authenticated enterprise or client context.

**Required capability:** `events.read`

**Parameters:**

- `scope_ref` `string` (query) — Topology perimeter for this operation. Pass the `b2b2x:tenant_ref` claim from your bearer token JWT payload.
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `from_date` `string` (query)
- `to_date` `string` (query)
- `actor_id` `string` (query)
- `aggregate_type` `string` (query)
- `aggregate_id` `string` (query)
- `event_type` `string` (query)
- `event_type_pattern` `string` (query)
- `trace_id` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "aggregate": {
          "type": "withdrawal",
          "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "data": {
          "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "status": "executed"
        },
        "event_type": "operations.withdrawal.executed.v1",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "metadata": null,
        "occurred_at": "2026-05-01T10:00:00Z",
        "partition_key": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "published_at": "2026-05-01T10:00:00Z",
        "resource": "event",
        "schema_version": 1,
        "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "trace_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capabilities."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### GET /events/{event_id}

**Get event**

**Required capability:** `events.read`

**Parameters:**

- `event_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "aggregate": {
      "type": "withdrawal",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "data": {
      "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "status": "executed"
    },
    "event_type": "operations.withdrawal.executed.v1",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "metadata": null,
    "occurred_at": "2026-05-01T10:00:00Z",
    "partition_key": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "published_at": "2026-05-01T10:00:00Z",
    "resource": "event",
    "schema_version": 1,
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "trace_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capabilities."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "event_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### POST /events/{event_id}/replay

**Replay event to webhook subscriptions**

Schedules webhook deliveries for a stored event. Omit `subscription_ids` to replay to every active matching subscription.

**Required capability:** `events.read`, `webhooks.manage`

**Parameters:**

- `event_id` `string` (path) *(required)*

**Request body** (`application/json`):

- `subscription_ids` `array`

**Request example:**

```json
{
  "subscription_ids": [
    "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  ]
}
```

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "accepted": true,
    "replayed_event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "targeted_subscription_ids": [
      "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_filter"
    },
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capabilities."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "event_not_found"
    },
    "message": "Resource not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "duplicate_webhook_subscription_request"
    },
    "message": "Idempotency conflict."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_applicable"
    },
    "message": "Request is not admissible."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

### GET /events/types

**List webhook event types**

Returns the canonical public webhook event catalog accepted by event filters and webhook subscriptions.

**Required capability:** `events.read`

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "domain": "operations",
        "event_type": "operations.withdrawal.settled.v1",
        "resource": "withdrawal",
        "schema_version": 1,
        "source_package": "@yh/operation-flow-contracts",
        "verb": "settled"
      }
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capabilities."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "event_backbone_storage_unavailable"
    },
    "message": "Service temporarily unavailable."
  }
  ```

## Withdrawals

### GET /withdrawals

**List withdrawals**

**Required capability:** `withdrawals.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)
- `from_date` `string` (query)
- `to_date` `string` (query)
- `asset` `string` (query)
- `min_amount` `string` (query)
- `sort` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "approval_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "destination_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "dispatch_attempt_id": null,
        "failure_reason": null,
        "family": "withdrawal",
        "family_flow_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fee_transaction_ids": [],
        "fill_rate": null,
        "hold_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "leg_attempt_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "network": "ethereum",
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "principal_transaction_id": null,
        "rail": "ethereum",
        "rail_class": "crypto",
        "release_transaction_id": null,
        "settled_at": null,
        "settlement_evidence": null,
        "status": "executing",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "updated_at": "2026-05-01T10:00:00Z",
        "withdrawal_attempt_id": null
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /withdrawals

**Create withdrawal**

Creates a withdrawal operation. For crypto requests, bind either a stored withdrawal destination (`destination_id`) or a one-time inline `destination` (`{address, memo}` plus `network`) — exactly one crypto destination path must be present. For fiat requests, bind a stored fiat withdrawal destination by its `withdrawal_destination_id`, resolved within the supplied `account_ref` scope; the canonical bank routing and the authoritative owner topology are sourced from the stored destination, never from the request body. Both rails flow through the same create path: a fiat withdrawal is admitted here and gated downstream solely by fiat-rails runtime readiness at dispatch time (it is no longer short-circuited at the edge). Successful responses return the operation snapshot — for an immediately admitted withdrawal the response may carry `status = "executing"` once operation-flow has written that state. Idempotent on `Idempotency-Key` or `client_idempotency_key`. Human callers must obtain a step-up confirmation via `POST /action-tokens` and submit it in the `X-Action-Token` header; service principals are exempt.

**Required capability:** `withdrawals.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.
- `X-Action-Token` `string` (header) *(required)* — Single-use step-up confirmation token bound to the server-canonical command for this request. Required for money-movement operations when the caller is a human user; pure service principals skip only this human-confirmation check and still pass normal authentication and capability guards. For withdrawals, obtain the token by calling `POST /action-tokens` with structured `withdrawal.create` preview details, then resubmit `POST /withdrawals` with the returned token in this header. Missing or invalid tokens produce `400` with `code` in {`action_token_required`, `action_token_rejected`}; an unreachable approval service produces `502 action_token_validation_failed`.

**Request body** (`application/json`):


**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "amount": {
    "currency": "EUR",
    "value": "100.00"
  },
  "rail": "fiat",
  "withdrawal_destination_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "withdrawal",
    "family_params": {},
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Step-up confirmation failed for a money-movement operation. `code` is one of: `action_token_required` (X-Action-Token header missing), `action_token_rejected` (token is unknown, expired, already consumed, or its server-canonical command binding does not match the current request). For withdrawals, obtain a fresh token via `POST /action-tokens` with structured `withdrawal.create` preview details and retry.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The withdrawal request payload is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "The idempotency key was already used with a different request payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "Blocked by RBAC policy.",
      "source": "rbac"
    },
    "message": "The withdrawal was rejected by an admissibility policy."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_unavailable"
    },
    "message": "The withdrawal service is temporarily unavailable. Retry after a short delay."
  }
  ```

### GET /withdrawals/{withdrawal_id}

**Get withdrawal**

**Required capability:** `withdrawals.read`

**Parameters:**

- `withdrawal_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "destination_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "dispatch_attempt_id": null,
    "failure_reason": null,
    "family": "withdrawal",
    "family_flow_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fee_transaction_ids": [],
    "fill_rate": null,
    "hold_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "leg_attempt_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "network": "ethereum",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "principal_transaction_id": null,
    "rail": "ethereum",
    "rail_class": "crypto",
    "release_transaction_id": null,
    "settled_at": null,
    "settlement_evidence": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z",
    "withdrawal_attempt_id": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The withdrawal was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /withdrawals/{withdrawal_id}/cancel

**Cancel withdrawal**

**Required capability:** `withdrawals.manage`

**Parameters:**

- `withdrawal_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "withdrawal",
    "family_params": {},
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The withdrawal was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "operation_not_cancellable"
    },
    "message": "The withdrawal is not in a cancellable state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Withdrawal Destinations

### GET /withdrawal-destinations

**List withdrawal destinations**

Lists withdrawal destinations for the selected rail. Crypto lists require `scope_ref` for the topology-scoped address book. Fiat lists require `account_ref`; the pooled fiat route owner is derived server-side and is not part of the request surface.

**Required capability:** `withdrawal_destinations.read`

**Parameters:**

- `rail_class` `string` (query) *(required)*
- `scope_ref` `string` (query) — Topology scope of the crypto address book. Required when rail_class=crypto; ignored for fiat.
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.
- `status` `string` (query)
- `asset` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `currency` `string` (query) — Currency code (ISO-4217 or on-chain ticker)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "asset": "USDC",
        "created_at": "2026-05-01T10:00:00Z",
        "crypto_routing": {
          "asset": "USDC",
          "destination": {
            "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
            "memo": null
          },
          "label": "My ETH wallet",
          "network": "ethereum"
        },
        "fiat_routing": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "label": "My ETH wallet",
        "rail_class": "crypto",
        "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "active",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### POST /withdrawal-destinations

**Register withdrawal destination**

Registers a crypto withdrawal destination with typed `{asset, network, destination: {address, memo}, label}` routing and `scope_ref`. Fiat destination creation requires `account_ref` and canonical fiat rails routing `{fiat_rail, method, currency, beneficiary_name, bank_coordinates, reference_hint}`; the pooled fiat route owner is derived server-side. The `Idempotency-Key` header is required: fiat creation rejects requests without it, and the crypto path forwards it for replay-safe provisioning.

**Required capability:** `withdrawal_destinations.create`

**Parameters:**

- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):


**Request example:**

```json
{
  "crypto_routing": {
    "asset": "USDC",
    "destination": {
      "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
      "memo": null
    },
    "label": "My ETH wallet",
    "network": "ethereum"
  },
  "rail_class": "crypto",
  "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "The destination is in a conflicting state for this operation."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### GET /withdrawal-destinations/{destination_id}

**Get withdrawal destination**

Reads a withdrawal destination by id. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat reads also require `account_ref` as the producer scope field; the pooled fiat route owner is derived server-side.

**Required capability:** `withdrawal_destinations.read`

**Parameters:**

- `destination_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "The withdrawal destination was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### PATCH /withdrawal-destinations/{destination_id}

**Update withdrawal destination**

Updates a crypto withdrawal destination with typed `{asset, network, destination: {address, memo}, label}` routing. Fiat updates require `account_ref` and canonical fiat rails routing `{fiat_rail, method, currency, beneficiary_name, bank_coordinates, reference_hint}`. The `Idempotency-Key` header is required: fiat updates reject requests without it; the crypto path accepts and ignores it.

**Required capability:** `withdrawal_destinations.manage`

**Parameters:**

- `destination_id` `string` (path) *(required)*
- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):


**Request example:**

```json
{
  "crypto_routing": {
    "asset": "USDC",
    "destination": {
      "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
      "memo": null
    },
    "label": "My Polygon wallet",
    "network": "polygon"
  },
  "rail_class": "crypto"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "The withdrawal destination was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "If-Match check failed; the resource has changed since the cached etag."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### POST /withdrawal-destinations/{destination_id}/disable

**Disable withdrawal destination**

Changes withdrawal destination state. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat state changes also require `account_ref`. The `Idempotency-Key` header is required: fiat state changes reject requests without it; the crypto path accepts and ignores it.

**Required capability:** `withdrawal_destinations.manage`

**Parameters:**

- `destination_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.
- `idempotency_key` `string` (query)
- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "The withdrawal destination was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "The destination is in a conflicting state for this operation."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### POST /withdrawal-destinations/{destination_id}/enable

**Enable withdrawal destination**

Changes withdrawal destination state. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat state changes also require `account_ref`. The `Idempotency-Key` header is required: fiat state changes reject requests without it; the crypto path accepts and ignores it.

**Required capability:** `withdrawal_destinations.manage`

**Parameters:**

- `destination_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.
- `idempotency_key` `string` (query)
- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "The withdrawal destination was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "The destination is in a conflicting state for this operation."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

### POST /withdrawal-destinations/{destination_id}/retire

**Retire withdrawal destination**

Changes withdrawal destination state. The `rail_class` query parameter is required so edge can route directly to the selected backend. Fiat state changes also require `account_ref`. The `Idempotency-Key` header is required: fiat state changes reject requests without it; the crypto path accepts and ignores it.

**Required capability:** `withdrawal_destinations.manage`

**Parameters:**

- `destination_id` `string` (path) *(required)*
- `rail_class` `string` (query) *(required)*
- `account_ref` `string` (query) — Operating account scope. Required when rail_class=fiat; ignored for crypto.
- `idempotency_key` `string` (query)
- `Idempotency-Key` `string` (header) *(required)* — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "asset": "USDC",
    "created_at": "2026-05-01T10:00:00Z",
    "crypto_routing": {
      "asset": "USDC",
      "destination": {
        "address": "0xAbCd1234567890AbCd1234567890AbCd12345678",
        "memo": null
      },
      "label": "My ETH wallet",
      "network": "ethereum"
    },
    "fiat_routing": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "label": "My ETH wallet",
    "rail_class": "crypto",
    "scope_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid (e.g. missing required field or unsupported rail)."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "message": "The withdrawal destination was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "message": "The destination is in a conflicting state for this operation."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "message": "The rail or provider is temporarily unavailable."
  }
  ```

## Internal Transfers

### GET /internal-transfers

**List internal transfers**

**Required capability:** `internal_transfers.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)
- `from_date` `string` (query)
- `to_date` `string` (query)
- `asset` `string` (query)
- `min_amount` `string` (query)
- `sort` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "approval_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "failure_reason": null,
        "family": "internal_transfer",
        "family_params": {
          "source_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "target_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fill_rate": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "settled_at": "2026-05-01T10:00:00Z",
        "status": "executed",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /internal-transfers

**Create internal transfer**

Initiates an internal transfer between two accounts inside the same tenant. Idempotent on `Idempotency-Key` or body `client_idempotency_key`.

**Required capability:** `internal_transfers.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):

- `amount` `object` *(required)*
  - `currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)
  - `value` `string` *(required)* — DecimalString
- `client_idempotency_key` `string`
- `source_ref` `string` *(required)*
- `target_ref` `string` *(required)*

**Request example:**

```json
{
  "amount": {
    "currency": "USDC",
    "value": "250.00"
  },
  "source_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "target_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "internal_transfer",
    "family_params": {
      "source_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "target_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request contains invalid or missing fields."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "A different request was already submitted with this idempotency key."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "rbac",
      "source": "rbac"
    },
    "message": "The operation was rejected by policy or RBAC."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_unavailable"
    },
    "message": "The service is temporarily unavailable. Retry after a short delay."
  }
  ```

### GET /internal-transfers/{internal_transfer_id}

**Get internal transfer**

**Required capability:** `internal_transfers.read`

**Parameters:**

- `internal_transfer_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "internal_transfer",
    "family_params": {
      "source_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "target_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The requested operation does not exist."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /internal-transfers/{internal_transfer_id}/cancel

**Cancel internal transfer**

**Required capability:** `internal_transfers.manage`

**Parameters:**

- `internal_transfer_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "internal_transfer",
    "family_params": {
      "source_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "target_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Principal does not hold the required capability."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The requested operation does not exist."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "operation_not_cancellable"
    },
    "message": "The operation is not in a cancellable state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Conversions

### GET /conversions

**List conversions**

Lists conversion operation snapshots. Preview responses are informational only; operation execution may recompute fees and rate before ledger posting, so reads must not be treated as a bound preview replay.

**Required capability:** `conversions.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.
- `status` `string` (query)
- `from_date` `string` (query)
- `to_date` `string` (query)
- `asset` `string` (query)
- `min_amount` `string` (query)
- `sort` `string` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "applied_rate": null,
        "approval_ref": null,
        "conversion_execution_id": null,
        "created_at": "2026-05-01T10:00:00Z",
        "failure_detail": null,
        "failure_reason": null,
        "family": "conversion",
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fee_transaction_ids": null,
        "fill_rate": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "ledger_posted_target_amount": null,
        "leg_attempt_id": null,
        "posted_at": null,
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "principal_transaction_id": null,
        "settled_at": null,
        "source_gross_amount": null,
        "source_principal_amount": null,
        "status": "executing",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "target_amount": null,
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /conversions

**Create conversion**

Initiates a conversion. Any prior preview is non-binding: conversion execution may recompute fees and rate before ledger posting. The response is the operation snapshot in `pending`/`in_progress` state — track via `GET /conversions/{id}`. Human callers must obtain a step-up confirmation via `POST /action-tokens` and submit it in the `X-Action-Token` header; service principals are exempt.

**Required capability:** `conversions.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.
- `X-Action-Token` `string` (header) *(required)* — Single-use step-up confirmation token bound to the server-canonical command for this request. Required for money-movement operations when the caller is a human user; pure service principals skip only this human-confirmation check and still pass normal authentication and capability guards. For withdrawals, obtain the token by calling `POST /action-tokens` with structured `withdrawal.create` preview details, then resubmit `POST /withdrawals` with the returned token in this header. Missing or invalid tokens produce `400` with `code` in {`action_token_required`, `action_token_rejected`}; an unreachable approval service produces `502 action_token_validation_failed`.

**Request body** (`application/json`):

- `account_ref` `string` *(required)*
- `client_idempotency_key` `string`
- `from_amount` `object` *(required)*
  - `currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)
  - `value` `string` *(required)* — DecimalString
- `to_currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)

**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "from_amount": {
    "currency": "USDC",
    "value": "250.00"
  },
  "to_currency": "BTC"
}
```

**Responses:**

- `202` — Request accepted for asynchronous processing. Poll the returned operation ID to track status transitions.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "withdrawal",
    "family_params": {},
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Step-up confirmation failed for a money-movement operation. `code` is one of: `action_token_required` (X-Action-Token header missing), `action_token_rejected` (token is unknown, expired, already consumed, or its server-canonical command binding does not match the current request). For withdrawals, obtain a fresh token via `POST /action-tokens` with structured `withdrawal.create` preview details and retry.

  ```json
  {
    "code": "action_token_required",
    "message": "A step-up action token is required for this operation."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "A request with the same idempotency key but a different payload already exists."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "upstream_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /conversions/{conversion_id}

**Get conversion**

Returns the current conversion operation snapshot. Preview economics are non-binding display data; settled execution may use recomputed fees and rate before ledger posting.

**Required capability:** `conversions.read`

**Parameters:**

- `conversion_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "applied_rate": null,
    "approval_ref": null,
    "conversion_execution_id": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_detail": null,
    "failure_reason": null,
    "family": "conversion",
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fee_transaction_ids": null,
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "ledger_posted_target_amount": null,
    "leg_attempt_id": null,
    "posted_at": null,
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "principal_transaction_id": null,
    "settled_at": null,
    "source_gross_amount": null,
    "source_principal_amount": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "target_amount": null,
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "conversion"
    },
    "message": "Conversion not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /conversions/{conversion_id}/cancel

**Cancel conversion**

**Required capability:** `conversions.manage`

**Parameters:**

- `conversion_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "withdrawal",
    "family_params": {},
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "message": "Caller lacks the required capability or permitted scope."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "conversion"
    },
    "message": "Conversion not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "operation_not_cancellable"
    },
    "message": "State conflict — the request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /conversions/preview

**Preview a conversion**

Returns a non-binding account-led conversion preview for display. `economics` names source gross amount, fee summary, source principal amount, indicative rate, and target amount explicitly; `binding` is always false. The preview does not reserve funds, lock a rate, or create an executable quote. Creating/executing a conversion may recompute fees and rate before ledger posting.

**Request body** (`application/json`):

- `account_ref` `string` *(required)*
- `from_amount` `object` *(required)*
  - `currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)
  - `value` `string` *(required)* — DecimalString
- `requested_at` `string`
- `to_currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)

**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "from_amount": {
    "currency": "USDC",
    "value": "250.00"
  },
  "to_currency": "BTC"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "binding": false,
    "calculated_at": "2026-05-01T10:00:00Z",
    "economics": {
      "binding": false,
      "fee_summary": {
        "components": [
          {
            "amount": {
              "currency": "USDC",
              "value": "1.00"
            },
            "kind": "network_fee"
          }
        ],
        "total": {
          "currency": "USDC",
          "value": "1.00"
        }
      },
      "indicative_rate": "65526.31",
      "source_gross_amount": {
        "currency": "USDC",
        "value": "250.00"
      },
      "source_principal_amount": {
        "currency": "USDC",
        "value": "249.00"
      },
      "target_amount": {
        "currency": "BTC",
        "value": "0.00380000"
      }
    },
    "expires_at": null,
    "fee_summary": {
      "components": [
        {
          "type": "network_fee",
          "amount": {
            "amount": "1.00",
            "currency": "USDC"
          },
          "payee_ref": null
        }
      ],
      "total": {
        "amount": "1.00",
        "currency": "USDC"
      }
    },
    "from_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "indicative_price": {
      "computed_at": "2026-05-01T10:00:00Z",
      "expires_at": null,
      "price": "65526.31",
      "price_type": "indicative",
      "provider_hint": null
    },
    "principal_amount": {
      "currency": "USDC",
      "value": "249.00"
    },
    "to_amount": {
      "currency": "BTC",
      "value": "0.00380000"
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "fee_total_exceeds_source"
    },
    "message": "Invalid request."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "fee_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Fee Previews

### POST /fee-previews

**Preview a fee**

Returns a non-binding fee preview for a planned operation. Pass `principal_amount` (and optionally `settlement_amount` for asymmetric flows like off-ramp). The response is wrapped in a `fee_preview` envelope.

**Request body** (`application/json`):

- `operation_type` `string` *(required)*
- `principal_amount` `object` *(required)*
  - `amount` `string` *(required)*
  - `currency` `string` *(required)*
- `requested_at` `string`
- `service_type` `string` *(required)*
- `settlement_amount` `object`
  - `amount` `string` *(required)*
  - `currency` `string` *(required)*
- `subject_ref` `string` *(required)*

**Request example:**

```json
{
  "operation_type": "withdrawal_crypto",
  "principal_amount": {
    "amount": "100.00",
    "currency": "USDC"
  },
  "requested_at": "2026-05-01T10:00:00Z",
  "service_type": "withdrawal_crypto",
  "settlement_amount": null,
  "subject_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "fee_preview": {
      "binding": "non_binding",
      "computed_at": "2026-05-01T10:00:00Z",
      "enterprise_ca_version": 2,
      "fee_summary": {
        "components": [
          {
            "type": "network_fee",
            "amount": {
              "amount": "1.00",
              "currency": "USDC"
            },
            "payee_ref": null
          }
        ],
        "total": {
          "amount": "1.00",
          "currency": "USDC"
        }
      },
      "operation_type": "withdrawal_crypto",
      "platform_ca_version": 1
    }
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "Missing required field: principal_amount"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "scope_not_covered"
    },
    "message": "subject_ref requires a bound tenant scope on this endpoint"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "A conflicting fee preview operation is already in progress."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "Fee preview request is not admissible for this subject."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Prices

### GET /prices/indicative

**Get indicative price**

Returns the raw non-binding exchange pricing envelope for a from-asset/to-asset pair. Specify either `from_amount` or `to_amount`; `amount_basis` indicates which side was sized. `account_ref` is required and validated server-side. This response is informational only; execution must request pricing again.

**Parameters:**

- `from_asset` `string` (query) *(required)*
- `to_asset` `string` (query) *(required)*
- `amount_basis` `string` (query) *(required)*
- `from_amount` `string` (query) — DecimalString
- `to_amount` `string` (query) — DecimalString
- `account_ref` `string` (query) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "amount_basis": "from",
    "binding": false,
    "calculated_at": "2026-05-01T10:00:00Z",
    "expires_at": "2026-05-01T10:00:00Z",
    "flow_type": "conversion",
    "from_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "from_asset": "USDC",
    "indicative_price": {
      "computed_at": "2026-05-01T10:00:00Z",
      "price": "65789.47",
      "price_type": "indicative"
    },
    "pricing_mode": "indicative",
    "to_amount": {
      "currency": "BTC",
      "value": "0.00380000"
    },
    "to_asset": "BTC"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "account_ref must be a valid AccountRef (e.g. client-accounts/<uuid>)"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "scope_not_covered"
    },
    "message": "account_ref requires a bound operating scope on this endpoint"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## User Invitations

### GET /user-invitations

**List user invitations**

Lists user invitations under an enterprise scope.

**Required capability:** `users.read`

**Parameters:**

- `enterprise_ref` `string` (query) *(required)*
- `status` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "accepted_at": null,
        "cancelled_at": null,
        "challenge_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "email_constraint": "jane.doe@acme.example",
        "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "etag": "W/\"a1b2c3d4\"",
        "expires_at": "2026-05-01T10:00:00Z",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "invited_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "pending_human_actor_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "status": "pending",
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "enterprise_admin_required"
    },
    "message": "Enterprise admin capability required"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_identity_unavailable"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /user-invitations

**Create user invitation**

Sends an e-mail invitation to a new user. The invitation links a role and scope to the recipient. Once accepted, the user is provisioned and the role assignment activated.

**Required capability:** `users.invite`

**Request body** (`application/json`):

- `display_name` `string`
- `email` `string` *(required)*
- `role` `string` *(required)*
- `scope` `string` *(required)*

**Request example:**

```json
{
  "display_name": "Jane Doe",
  "email": "jane.doe@acme.example",
  "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "invitation": {
      "accepted_at": null,
      "cancelled_at": null,
      "challenge_ref": null,
      "created_at": "2026-05-01T10:00:00Z",
      "email_constraint": "jane.doe@acme.example",
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "etag": "W/\"a1b2c3d4\"",
      "expires_at": "2026-05-01T10:00:00Z",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "invited_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "pending_human_actor_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "status": "pending",
      "updated_at": "2026-05-01T10:00:00Z"
    },
    "status": "pending"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "enterprise_admin_required"
    },
    "message": "Enterprise admin capability required"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_identity_unavailable"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### GET /user-invitations/{invitation_id}

**Get user invitation**

**Required capability:** `users.read`

**Parameters:**

- `invitation_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "accepted_at": null,
    "cancelled_at": null,
    "challenge_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "email_constraint": "jane.doe@acme.example",
    "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "expires_at": "2026-05-01T10:00:00Z",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "invited_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "pending_human_actor_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "pending",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "enterprise_admin_required"
    },
    "message": "Enterprise admin capability required"
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "resource_not_found",
    "details": {
      "reason": "invitation_not_found"
    },
    "message": "The requested invitation does not exist"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_identity_unavailable"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /user-invitations/accept

**Accept user invitation**

Public endpoint — no Bearer token required. The invitation recipient submits `(invitation_id, challenge_ref)` received via the magic-link e-mail. On success the response contains a short-lived `session_token` that the client can use for a platform session.

**Request body** (`application/json`):

- `challenge_ref` `string` *(required)*
- `invitation_id` `string` *(required)*

**Request example:**

```json
{
  "challenge_ref": "challenge-ref-0001",
  "invitation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "actor_scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "invitation": {
      "accepted_at": "2026-05-01T10:00:00Z",
      "cancelled_at": null,
      "challenge_ref": null,
      "created_at": "2026-05-01T10:00:00Z",
      "email_constraint": "jane.doe@acme.example",
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "etag": "W/\"a1b2c3d4\"",
      "expires_at": "2026-05-01T10:00:00Z",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "invited_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "pending_human_actor_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "status": "accepted",
      "updated_at": "2026-05-01T10:00:00Z"
    },
    "session_expires_at": "2026-05-01T10:00:00Z",
    "session_token": "sess_eyJhbGciOiJSUzI1NiJ9.payload.sig"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_identity_unavailable"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

### POST /user-invitations/cancel

**Cancel user invitation**

Cancels a pending invitation. Requires `If-Match` for optimistic concurrency. The invitation `id` and optional `reason` are supplied in the request body.

**Required capability:** `users.invite`

**Parameters:**

- `If-Match` `string` (header) *(required)* — Weak entity tag from a prior GET. Mismatch causes the request to fail with 412 Precondition Failed.

**Request body** (`application/json`):

- `invitation_id` `string` *(required)*
- `reason` `string`

**Request example:**

```json
{
  "invitation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "reason": "User withdrew their request"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "accepted_at": null,
    "cancelled_at": "2026-05-01T10:00:00Z",
    "challenge_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "email_constraint": "jane.doe@acme.example",
    "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "etag": "W/\"a1b2c3d4\"",
    "expires_at": "2026-05-01T10:00:00Z",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "invited_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "pending_human_actor_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "role": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "scope": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "status": "cancelled",
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "A required field is missing or invalid"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "enterprise_admin_required"
    },
    "message": "Enterprise admin capability required"
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `412` — If-Match check failed; the resource has changed since the cached etag.

  ```json
  {
    "code": "precondition_failed",
    "details": {
      "reason": "etag_mismatch"
    },
    "message": "The If-Match value does not match the current ETag"
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "downstream_identity_unavailable"
    },
    "message": "A downstream service is temporarily unavailable"
  }
  ```

## On-ramp Sessions

### GET /on-ramp-sessions

**List on-ramp sessions**

**Required capability:** `ramps.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "approval_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "failure_reason": null,
        "family": "on_ramp",
        "family_params": {
          "source_rail": "crypto",
          "target_currency": "USDC"
        },
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fill_rate": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "settled_at": "2026-05-01T10:00:00Z",
        "status": "executed",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /on-ramp-sessions

**Create on-ramp session**

Initiates an on-ramp session. `amount` is the expected inbound principal; `target_currency` is the asset the account will receive after conversion; `source_rail` selects the inbound funding rail (`fiat` or `crypto`). Idempotent on `Idempotency-Key`.

**Required capability:** `ramps.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):

- `account_ref` `string` *(required)*
- `amount` `object` *(required)*
  - `currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)
  - `value` `string` *(required)* — DecimalString
- `client_idempotency_key` `string`
- `destination` `object`
- `source_rail` `string` *(required)*
- `target_currency` `string` *(required)*

**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "amount": {
    "currency": "USDC",
    "value": "250.00"
  },
  "source_rail": "crypto",
  "target_currency": "USDC"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "on_ramp",
    "family_params": {
      "source_rail": "crypto",
      "target_currency": "USDC"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request payload is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "The idempotency key was already used with a different request payload."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "Operation blocked by RBAC policy.",
      "source": "rbac"
    },
    "message": "The operation was rejected by an admissibility policy."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_unavailable"
    },
    "message": "The on-ramp service is temporarily unavailable. Retry after a short delay."
  }
  ```

### GET /on-ramp-sessions/{session_id}

**Get on-ramp session**

**Required capability:** `ramps.read`

**Parameters:**

- `session_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "on_ramp",
    "family_params": {
      "source_rail": "crypto",
      "target_currency": "USDC"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The on-ramp session was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /on-ramp-sessions/{session_id}/cancel

**Cancel on-ramp session**

**Required capability:** `ramps.manage`

**Parameters:**

- `session_id` `string` (path) *(required)*

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "on_ramp",
    "family_params": {
      "source_rail": "crypto",
      "target_currency": "USDC"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": "2026-05-01T10:00:00Z",
    "status": "executed",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The on-ramp session was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "operation_not_cancellable"
    },
    "message": "The on-ramp session cannot be cancelled in its current state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Off-ramp Sessions

### GET /off-ramp-sessions

**List off-ramp sessions**

**Required capability:** `ramps.read`

**Parameters:**

- `account_ref` `string` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "approval_ref": null,
        "created_at": "2026-05-01T10:00:00Z",
        "failure_reason": null,
        "family": "off_ramp",
        "family_params": {
          "source_currency": "USDC",
          "target_rail": "fiat"
        },
        "fee_summary": {
          "components": [
            {
              "amount": {
                "currency": "USDC",
                "value": "1.00"
              },
              "kind": "network_fee"
            }
          ],
          "total": {
            "currency": "USDC",
            "value": "1.00"
          }
        },
        "fill_rate": null,
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "principal_amount": {
          "currency": "USDC",
          "value": "250.00"
        },
        "settled_at": null,
        "status": "executing",
        "subject_attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "enterprise_binding": {
            "tenant_type": "enterprise",
            "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "federation": null,
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
            "kind": "user",
            "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "updated_at": "2026-05-01T10:00:00Z"
      }
    ],
    "next_page_token": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /off-ramp-sessions

**Create off-ramp session**

Initiates an off-ramp session. `amount` is the principal to debit from the account; `target_currency` is the asset the recipient will receive; `target_rail` selects the outbound delivery rail (`fiat` or `crypto`), and `destination` carries the matching typed withdrawal destination command. Idempotent on `Idempotency-Key`.

**Required capability:** `ramps.create`

**Parameters:**

- `Idempotency-Key` `string` (header) — Client-generated idempotency key. 1-128 ASCII characters. Two requests with the same key are treated as a single operation.

**Request body** (`application/json`):

- `account_ref` `string` *(required)*
- `amount` `object` *(required)*
  - `currency` `string` *(required)* — Currency code (ISO-4217 or on-chain ticker)
  - `value` `string` *(required)* — DecimalString
- `client_idempotency_key` `string`
- `destination` `object`
- `target_currency` `string` *(required)*
- `target_rail` `string` *(required)*

**Request example:**

```json
{
  "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "amount": {
    "currency": "USDC",
    "value": "250.00"
  },
  "destination": {
    "destination": {
      "bank_coordinates": {
        "account_holder_name": "Acme Treasury",
        "bank_name": "Demo Bank",
        "bic": "NWBKGB2L",
        "country": "GB",
        "iban": "GB29NWBK60161331926819",
        "scheme": "iban"
      },
      "beneficiary_name": "Acme Treasury",
      "currency": "EUR",
      "fiat_rail": "sepa_credit_transfer",
      "method": "bank_transfer",
      "reference_hint": null
    },
    "fiat_rail": "sepa_credit_transfer",
    "method": "bank_transfer",
    "payment_reference": "RF18539007547034",
    "route_owner_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "withdrawal_destination_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  },
  "target_currency": "EUR",
  "target_rail": "fiat"
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "off_ramp",
    "family_params": {
      "source_currency": "USDC",
      "target_rail": "fiat"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "missing_required_field"
    },
    "message": "The request contains invalid or missing fields."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "idempotency_conflict",
    "details": {
      "reason": "key_payload_mismatch"
    },
    "message": "A different request was already submitted with this idempotency key."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "policy_rejected",
      "source": "policy"
    },
    "message": "The operation was rejected by policy checks."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_unavailable"
    },
    "message": "The service is temporarily unavailable. Please retry."
  }
  ```

### GET /off-ramp-sessions/{session_id}

**Get off-ramp session**

**Required capability:** `ramps.read`

**Parameters:**

- `session_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "off_ramp",
    "family_params": {
      "source_currency": "USDC",
      "target_rail": "fiat"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The requested off-ramp session was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /off-ramp-sessions/{session_id}/cancel

**Cancel off-ramp session**

**Required capability:** `ramps.manage`

**Parameters:**

- `session_id` `string` (path) *(required)*

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "account_ref": "client-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "approval_ref": null,
    "created_at": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "family": "off_ramp",
    "family_params": {
      "source_currency": "USDC",
      "target_rail": "fiat"
    },
    "fee_summary": {
      "components": [
        {
          "amount": {
            "currency": "USDC",
            "value": "1.00"
          },
          "kind": "network_fee"
        }
      ],
      "total": {
        "currency": "USDC",
        "value": "1.00"
      }
    },
    "fill_rate": null,
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "principal_amount": {
      "currency": "USDC",
      "value": "250.00"
    },
    "settled_at": null,
    "status": "executing",
    "subject_attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "enterprise_binding": {
        "tenant_type": "enterprise",
        "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "federation": null,
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "kind": "user",
        "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "updated_at": "2026-05-01T10:00:00Z"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "not_found",
    "details": {
      "resource": "operation"
    },
    "message": "The requested off-ramp session was not found."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "operation_not_cancellable"
    },
    "message": "The operation cannot be cancelled in its current state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## Operations Activity Exports

### GET /operations-activity-exports

**List operations activity exports**

**Required capability:** `operations_reports.read`

**Parameters:**

- `requested_scope` `string` (query)
- `status` `string` (query)
- `limit` `integer` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "format": "csv",
        "byte_size": 32768,
        "download_path": "/operations-activity-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
        "expires_at_utc": "2026-05-01T10:00:00Z",
        "failure_reason": null,
        "filter_criteria": {
          "date_from_utc": "2026-04-01T00:00:00Z",
          "date_to_utc": "2026-04-30T23:59:59Z"
        },
        "finished_at_utc": "2026-05-01T10:00:00Z",
        "generated_at_utc": "2026-05-01T10:00:00Z",
        "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "requested_scope": {
          "kind": "enterprise",
          "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "row_count": 150,
        "status": "ready",
        "storage_location": "s3://bucket/exports/ops-001.csv"
      }
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /operations-activity-exports

**Create operations activity export**

**Required capability:** `operations_reports.create_export`

**Request body** (`application/json`):

- `format` `string` *(required)*
- `filter_criteria` `object` *(required)*
  - `assets` `array`
  - `client_account_refs` `array`
  - `client_refs` `array`
  - `date_from_utc` `string` *(required)*
  - `date_to_utc` `string` *(required)*
  - `failure_reason_codes` `array`
  - `operation_families` `array`
  - `statuses` `array`
- `requested_scope` `any` *(required)*

**Request example:**

```json
{
  "format": "csv",
  "filter_criteria": {
    "date_from_utc": "2026-04-01T00:00:00Z",
    "date_to_utc": "2026-04-30T23:59:59Z"
  },
  "requested_scope": {
    "kind": "enterprise",
    "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "format": "csv",
    "byte_size": 32768,
    "download_path": "/operations-activity-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
    "expires_at_utc": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "filter_criteria": {
      "date_from_utc": "2026-04-01T00:00:00Z",
      "date_to_utc": "2026-04-30T23:59:59Z"
    },
    "finished_at_utc": "2026-05-01T10:00:00Z",
    "generated_at_utc": "2026-05-01T10:00:00Z",
    "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requested_scope": {
      "kind": "enterprise",
      "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "row_count": 150,
    "status": "ready",
    "storage_location": "s3://bucket/exports/ops-001.csv"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_date_range"
    },
    "message": "The export request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /operations-activity-exports/{export_id}

**Get operations activity export**

**Required capability:** `operations_reports.read`

**Parameters:**

- `export_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "format": "csv",
    "byte_size": 32768,
    "download_path": "/operations-activity-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
    "expires_at_utc": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "filter_criteria": {
      "date_from_utc": "2026-04-01T00:00:00Z",
      "date_to_utc": "2026-04-30T23:59:59Z"
    },
    "finished_at_utc": "2026-05-01T10:00:00Z",
    "generated_at_utc": "2026-05-01T10:00:00Z",
    "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requested_scope": {
      "kind": "enterprise",
      "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "row_count": 150,
    "status": "ready",
    "storage_location": "s3://bucket/exports/ops-001.csv"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "export_not_found",
    "details": {
      "reason": "export_not_found"
    },
    "message": "The requested operations activity export was not found."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /operations-activity-exports/{export_id}/download

**Download operations activity export file**

Proxies the binary export artefact (CSV or JSON). The bucket layout, region, and credentials never leak past the perimeter.

**Required capability:** `operations_reports.read`

**Parameters:**

- `export_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  ""
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "export_not_found",
    "details": {
      "reason": "export_not_found"
    },
    "message": "The export file is not available for download."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## User Action Audit Entries

### GET /user-action-audit-entries/{entry_id}

**Get audit log entry**

**Required capability:** `audit.read`

**Parameters:**

- `entry_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "action_family": "tenant_governance",
    "approval_state": "not_required",
    "attribution": {
      "actor": null,
      "approved_by": null,
      "authenticated_principal": {
        "kind": "user",
        "ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      },
      "identity_source": "platform-managed",
      "initiated_by": null,
      "subject": {
        "kind": "user",
        "ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
      }
    },
    "changed_fields": null,
    "correlation_id": null,
    "detail": null,
    "event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "event_type": "tenant.enterprise.admitted.v1",
    "human_actor_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "occurred_at_utc": "2026-05-01T10:00:00Z",
    "reason_code": null,
    "reason_text": null,
    "recorded_at_utc": "2026-05-01T10:00:00Z",
    "request_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource_type": "enterprise",
    "result_status": "succeeded",
    "scope": {
      "client_account_ref": null,
      "client_ref": null,
      "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "master_account_ref": null,
      "platform_operator_ref": null
    },
    "service_account_id": null,
    "source_service": "edge-service",
    "trace_id": null
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "entry_not_found",
    "details": {
      "reason": "action_audit_entry_not_found"
    },
    "message": "Audit entry not found"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /user-action-audit-entries/search

**Search audit log entries**

Queries the immutable audit trail. `occurred_from_utc` and `occurred_to_utc` are required. All other filters are optional.

**Required capability:** `audit.read`

**Parameters:**

- `enterprise_ref` `string` (query)
- `platform_operator_ref` `string` (query)
- `master_account_ref` `string` (query)
- `client_ref` `string` (query)
- `client_account_ref` `string` (query)
- `authenticated_principal` `string` (query)
- `subject` `string` (query)
- `actor` `string` (query)
- `resource_ref` `string` (query)
- `source_service` `string` (query)
- `event_types` `array` (query)
- `action_families` `array` (query)
- `result_statuses` `array` (query)
- `reason_codes` `array` (query)
- `occurred_from_utc` `string` (query) *(required)*
- `occurred_to_utc` `string` (query) *(required)*
- `limit` `integer` (query)
- `offset` `integer` (query)

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "action_family": "tenant_governance",
        "approval_state": "not_required",
        "attribution": {
          "actor": null,
          "approved_by": null,
          "authenticated_principal": {
            "kind": "user",
            "ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          },
          "identity_source": "platform-managed",
          "initiated_by": null,
          "subject": {
            "kind": "user",
            "ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
          }
        },
        "changed_fields": null,
        "correlation_id": null,
        "detail": null,
        "event_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "event_type": "tenant.enterprise.admitted.v1",
        "human_actor_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "occurred_at_utc": "2026-05-01T10:00:00Z",
        "reason_code": null,
        "reason_text": null,
        "recorded_at_utc": "2026-05-01T10:00:00Z",
        "request_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "resource_type": "enterprise",
        "result_status": "succeeded",
        "scope": {
          "client_account_ref": null,
          "client_ref": null,
          "enterprise_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "master_account_ref": null,
          "platform_operator_ref": null
        },
        "service_account_id": null,
        "source_service": "edge-service",
        "trace_id": null
      }
    ],
    "limit": 100,
    "offset": 0,
    "total": 1
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_date_range"
    },
    "message": "Date range is invalid or too wide"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

## User Action Audit Exports

### GET /user-action-audit-exports

**List audit exports**

**Required capability:** `audit.read`

**Parameters:**

- `status` `string` (query)
- `limit` `integer` (query)
- `page_size` `integer` (query) — Cursor pagination page size. The canonical contract accepts integers from 1 to 500.
- `page_token` `string` (query) — Opaque cursor returned by a previous page.

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "items": [
      {
        "format": "csv",
        "byte_size": 8192,
        "download_path": "/user-action-audit-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
        "expires_at_utc": "2026-05-01T10:00:00Z",
        "failure_reason": null,
        "filter_criteria": {
          "occurred_from_utc": "2026-04-01T00:00:00Z",
          "occurred_to_utc": "2026-04-30T23:59:59Z"
        },
        "finished_at_utc": "2026-05-01T10:00:00Z",
        "generated_at_utc": "2026-05-01T10:00:00Z",
        "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "requested_scope": {
          "kind": "enterprise",
          "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "row_count": 42,
        "status": "ready",
        "storage_location": "s3://bucket/exports/audit-001.csv"
      }
    ]
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### POST /user-action-audit-exports

**Create audit export**

**Required capability:** `audit.create_export`

**Request body** (`application/json`):

- `format` `string` *(required)*
- `filter_criteria` `object` *(required)*
  - `action_families` `array`
  - `actor` `string`
  - `authenticated_principal` `string`
  - `event_types` `array`
  - `occurred_from_utc` `string` *(required)*
  - `occurred_to_utc` `string` *(required)*
  - `reason_codes` `array`
  - `resource_ref` `string`
  - `result_statuses` `array`
  - `subject` `string`
- `requested_scope` `any` *(required)*

**Request example:**

```json
{
  "format": "csv",
  "filter_criteria": {
    "occurred_from_utc": "2026-04-01T00:00:00Z",
    "occurred_to_utc": "2026-04-30T23:59:59Z"
  },
  "requested_scope": {
    "kind": "enterprise",
    "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
  }
}
```

**Responses:**

- `201` — Resource created successfully.

  ```json
  {
    "format": "csv",
    "byte_size": 8192,
    "download_path": "/user-action-audit-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
    "expires_at_utc": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "filter_criteria": {
      "occurred_from_utc": "2026-04-01T00:00:00Z",
      "occurred_to_utc": "2026-04-30T23:59:59Z"
    },
    "finished_at_utc": "2026-05-01T10:00:00Z",
    "generated_at_utc": "2026-05-01T10:00:00Z",
    "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requested_scope": {
      "kind": "enterprise",
      "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "row_count": 42,
    "status": "ready",
    "storage_location": "s3://bucket/exports/audit-001.csv"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "details": {
      "reason": "invalid_date_range"
    },
    "message": "Date range is invalid or too wide"
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `409` — State conflict — the request cannot be applied to the current resource state.

  ```json
  {
    "code": "state_conflict",
    "details": {
      "reason": "state_conflict"
    },
    "message": "The request cannot be applied to the current resource state."
  }
  ```
- `422` — Operation is not admissible — it violates a business rule, policy constraint, or lifecycle precondition specific to this resource.

  ```json
  {
    "code": "not_admissible",
    "details": {
      "reason": "not_admissible"
    },
    "message": "The operation is not admissible in the current state."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /user-action-audit-exports/{export_id}

**Get audit export**

**Required capability:** `audit.read`

**Parameters:**

- `export_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  {
    "format": "csv",
    "byte_size": 8192,
    "download_path": "/user-action-audit-exports/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b/download",
    "expires_at_utc": "2026-05-01T10:00:00Z",
    "failure_reason": null,
    "filter_criteria": {
      "occurred_from_utc": "2026-04-01T00:00:00Z",
      "occurred_to_utc": "2026-04-30T23:59:59Z"
    },
    "finished_at_utc": "2026-05-01T10:00:00Z",
    "generated_at_utc": "2026-05-01T10:00:00Z",
    "generated_by": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "requested_scope": {
      "kind": "enterprise",
      "ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    },
    "row_count": 42,
    "status": "ready",
    "storage_location": "s3://bucket/exports/audit-001.csv"
  }
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "export_not_found",
    "details": {
      "reason": "export_not_found"
    },
    "message": "Audit export not found"
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```

### GET /user-action-audit-exports/{export_id}/download

**Download audit export file**

Proxies the binary export artefact (CSV or JSON). The bucket layout, region, and credentials never leak past the perimeter.

**Required capability:** `audit.read`

**Parameters:**

- `export_id` `string` (path) *(required)*

**Responses:**

- `200` — Operation succeeded.

  ```json
  ""
  ```
- `400` — Invalid request payload, query, or parameter shape.

  ```json
  {
    "code": "invalid_request",
    "message": "The request is invalid."
  }
  ```
- `401` — Caller is not authenticated or the bearer token is invalid.

  ```json
  {
    "code": "unauthorized",
    "message": "Authentication required."
  }
  ```
- `403` — Caller lacks the required capability or permitted scope.

  ```json
  {
    "code": "forbidden_capability_scope",
    "details": {
      "reason": "missing_capability"
    },
    "message": "Insufficient capability for this operation."
  }
  ```
- `404` — Resource not found.

  ```json
  {
    "code": "export_not_found",
    "details": {
      "reason": "export_not_found"
    },
    "message": "The audit export file is not available for download."
  }
  ```
- `429` — Request rate limit exceeded. Retry after the delay indicated in the `details.retry_after_ms` field.

  ```json
  {
    "code": "rate_limited",
    "details": {
      "retry_after_ms": 5000
    },
    "message": "Too many requests."
  }
  ```
- `502` — Upstream service returned an unexpected error.

  ```json
  {
    "code": "upstream_error",
    "message": "An upstream service returned an unexpected error."
  }
  ```
- `503` — Service is temporarily unavailable; retry with backoff.

  ```json
  {
    "code": "temporarily_unavailable",
    "details": {
      "reason": "service_temporarily_unavailable"
    },
    "message": "Service is temporarily unavailable."
  }
  ```
