> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.prividium.com/api/mcp` to find what you need.
>
> **Have feedback?** Use `submit_feedback` on the same MCP server.

:::info[Authentication]
All routes require authentication, membership in the deployment's organization and the route's permission (see the
[overview](/developers/asset-instructions/overview)).
:::

## Routes

| Method | Path                                               | Result                                                                                  |
| ------ | -------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `POST` | `/api/asset-instructions/operations`               | `202` accepted; identical retry `200`; changed payload, taken sequence or gap `409`     |
| `POST` | `/api/asset-instructions/corrections`              | Same body and the operation it reverses, if any; executed under an independent approval |
| `GET`  | `/api/asset-instructions/operations`               | Records newest first, with filters                                                      |
| `GET`  | `/api/asset-instructions/operations/{operationId}` | One record, with `execution` once confirmed                                             |
| `GET`  | `/api/asset-instructions/overview`                 | The next expected sequence, the instruction holding it and a count per state            |

## Submit an instruction

```bash
curl -X POST "http://localhost:8000/api/asset-instructions/operations" \
  -H "Authorization: Bearer <M2M_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "mint",
    "account": "CLIENT-OMNIBUS",
    "amount": "250000",
    "sequence": 12,
    "source": {
      "system": "LEDGER",
      "eventId": "fund-2026-09-18-0042",
      "eventType": "DEPOSIT",
      "timestamp": "2026-09-18T09:30:00Z"
    }
  }'
```

| Field              | Meaning                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------- |
| `operation`        | `mint` or `burn`; must match what the profile maps `source.eventType` to                    |
| `account`          | An account code from the deployment's instruction profile                                   |
| `amount`           | Positive integer string in the asset's minor units — a `uint256` does not fit a JSON number |
| `sequence`         | Positive integer; the deployment's single stream starts at `1` and executes in order        |
| `source.system`    | A source system the profile defines and the caller is bound to                              |
| `source.eventId`   | Your identifier for the business event, unique within the source system                     |
| `source.eventType` | An event type the profile maps to the operation                                             |
| `source.timestamp` | ISO 8601 time of the event                                                                  |

`202` means durable acceptance, not execution. The response is the instruction record:

```json
{
  "transactionId": "5f1c1c2e-2b7e-4a7a-9a5f-0d3c2e1f4b6a",
  "operationId": "0x9a3e…",
  "sequence": 12,
  "state": "RECEIVED",
  "stage": "AWAITING_POLICY",
  "instruction": {
    "kind": "OPERATION",
    "operation": "mint",
    "account": "CLIENT-OMNIBUS",
    "amount": "250000",
    "sequence": 12,
    "source": {
      "system": "LEDGER",
      "eventId": "fund-2026-09-18-0042",
      "eventType": "DEPOSIT",
      "timestamp": "2026-09-18T09:30:00Z"
    }
  },
  "createdAt": "2026-09-18T09:30:01.204Z",
  "updatedAt": "2026-09-18T09:30:01.204Z"
}
```

`operationId` is the `keccak256` of the deployment and the source identity (`organizationId`, `logicalAssetId`,
`source.system`, `source.eventId`). It is stable across retries and contract upgrades, and it is the id the contract
records on chain.

### Retries and conflicts

Resend the identical body and you get `200` with the existing record. A body that differs for the same `source.system`
and `source.eventId`, including a correction's `correctedOperationId`, or a `sequence` another instruction already
holds, is refused with `409 SEQUENCE_CONFLICT`. A `sequence` whose predecessor has not been accepted yet is refused with
`409 SEQUENCE_GAP`; submit it again once the predecessor is accepted. Unknown account codes, source systems or event
types, an amount above the `uint256` maximum, and a source system the caller is not bound to, are `400`.

### Corrections

`POST /api/asset-instructions/corrections` takes the same body plus an optional `correctedOperationId`: the
`operationId` of the ordinary operation the correction reverses, as its acceptance returned it. Without it the
correction is an adjustment that reverses no single operation, such as an aggregate reconciliation break. A correction
is executed by the deployment's separate correction signer through `correctMint` / `correctBurn`, which record the
reversed operation on chain (zero for an adjustment), and its approval must come from an approver who is neither the
submitter nor the signer. Corrections share the sequence stream with ordinary operations.

A linked correction is refused with `400 INVALID_INPUT_ERROR` when the reversed operation does not qualify, and
`error.message` says why:

| `error.message`                          | Meaning                                                               |
| ---------------------------------------- | --------------------------------------------------------------------- |
| `CORRECTED_OPERATION_NOT_FOUND`          | No instruction has that `operationId`                                 |
| `CORRECTED_OPERATION_NOT_COMPLETED`      | It is a correction, or an operation that has not completed            |
| `CORRECTED_OPERATION_DIRECTION_MISMATCH` | It moves in the same direction; a correcting `burn` reverses a `mint` |
| `CORRECTED_OPERATION_ACCOUNT_MISMATCH`   | It is on another `account`                                            |

The amount is not compared: a correction may reverse part of an operation.

## Follow an instruction

Poll `GET /api/asset-instructions/operations/{operationId}` and read `state` and `stage`:

| `state`                | Meaning                                                                    |
| ---------------------- | -------------------------------------------------------------------------- |
| `RECEIVED`             | Accepted; waiting for its turn, for the policy decision or for an approval |
| `READY_FOR_PROCESSING` | Authorized; execution starts when it reaches the head of the stream        |
| `PROCESSING`           | Being signed, broadcast or confirmed                                       |
| `COMPLETED`            | Confirmed on chain; `execution` carries the evidence                       |
| `FAILED`               | Refused, reverted or closed by an operator; `error` says why               |

`stage` is the detail behind `state`: `AWAITING_POLICY`, `AWAITING_APPROVAL` (a human approval is needed in the Admin
Panel), `AUTHORIZED`, `SIGNING`, `SIGNED`, `CONFIRMING`, `CONFIRMED`, `UNCERTAIN` (the broadcast outcome is unknown and
the stream waits), `POLICY_DENIED` then `POLICY_REJECTED` (closed; the sequence is released), `OPERATOR_CLOSED` (closed
by an operator; the sequence is released), `AUTHORIZATION_DENIED`, `CONTRACT_REVERT`, `ONCHAIN_REVERT`,
`RECEIPT_MISMATCH`, `NONCE_CONSUMED`, `INVALID_INSTRUCTION`, `EXECUTION_STATE_INVALID`, `SIGNING_REJECTED`,
`SIGNING_INVALID`, `AUTHORIZATION_UNAVAILABLE`, `WALLET_NOT_CONFIGURED`, `SIGNING_UNCERTAIN` and `RPC_UNAVAILABLE`.

`error` is present while an instruction is failed or waiting on something. When policy decided the outcome it is one of
these codes:

| `error`                        | Meaning                                                                                  |
| ------------------------------ | ---------------------------------------------------------------------------------------- |
| `POLICY_BLOCKED`               | A policy rule blocked the call                                                           |
| `APPROVAL_REJECTED`            | An approver rejected the required approval                                               |
| `APPROVAL_EXPIRED`             | The required approval expired before it was decided                                      |
| `APPROVAL_CANCELLED`           | The required approval was cancelled                                                      |
| `APPROVAL_INVALIDATED`         | A ruleset publish invalidated the pending approval                                       |
| `POLICY_AUTHORIZATION_EXPIRED` | The decision aged past the admit window before it was used; a new one has been requested |

Match on these codes and on `stage`, never on the stage name `POLICY_DENIED`. For every other stage `error` carries the
cause as text for people, such as a decoded contract revert or an RPC error; it is not a stable value.

A completed record's `execution` holds the on-chain evidence: `operationId`, `relatedOperationId` (the operation a
correction reverses, otherwise zero), `operation`, `kind`, `operationType` (`ISSUANCE`, `REDEMPTION`,
`CORRECTIVE_ISSUANCE`, `CORRECTIVE_REDEMPTION`), `account { name, walletId, wallet }`, `amount`, `operator`,
`resultingBalance`, `resultingSupply`, `transactionHash`, `blockNumber`, `blockHash` and `logIndex`.

The stream never skips. An instruction that ends `FAILED` — other than a policy denial before signing — holds its
sequence until an operator [retries or closes it](/developers/asset-instructions/recovery). An interrupted broadcast
resends the stored signed transaction when execution resumes, under a fresh policy decision once the admit window has
passed; nothing is rebuilt or re-signed automatically.

## List and overview

`GET /api/asset-instructions/operations` returns records newest first together with `total`. Filter with `state`,
`account`, `kind` (`OPERATION` or `CORRECTION`), `sequence`, `sourceSystem`, `sourceEventId`, `transactionId` and
`transactionHash`; page with `limit` (default 100, at most 500) and `offset`.

`GET /api/asset-instructions/overview` returns the next sequence the stream expects, a count per state and, once it has
arrived, the instruction at that sequence. While an operator
[holds execution](/developers/asset-instructions/recovery#hold-execution) it also returns `hold { since, reason }`:
instructions are still accepted, but none starts. A halted stream shows at the cursor why it stopped:

```json
{
  "nextExpected": 13,
  "states": [
    { "state": "COMPLETED", "count": 12 },
    { "state": "FAILED", "count": 1 }
  ],
  "cursor": {
    "operationId": "0x9a3e…",
    "state": "FAILED",
    "stage": "CONTRACT_REVERT",
    "error": "WalletFrozen(0x4444…)",
    "updatedAt": "2026-09-18T09:31:12.408Z"
  }
}
```
