# Upgrade an integration to 3.2

Source: https://docs.settlemint.com/docs/api-reference/guides/upgrade-to-3-2
Every change in DALP 3.2 that can break a client built against 3.1 or 3.0: removed operations, new required fields, new refusals, the SDK and the CLI.

DALP 3.2 changes the Platform API, the TypeScript SDK and the CLI in ways that can break a client written for DALP 3.1 or 3.0. Each change lists what changed, who is affected, how to detect it and what to do. The steps for the people who run the platform, such as the Helm upgrade, are on [Upgrade a deployment to DALP 3.2](https://docs.settlemint.com/docs/deployment/upgrade-to-3-2).

The v2 API is stable from DALP 3.2. Before 3.2, v2 could change between releases, and this page lists the changes it took up to 3.2. From 3.2 onward a breaking change to v2 ships only on a new API version, after a deprecation with at least 90 days' notice, as [Versioning and deprecation](https://docs.settlemint.com/docs/api-reference/guides/versioning-and-deprecation) describes.

## Start here [#start-here]

Regenerate your client from the 3.2 OpenAPI document and compile it before you read the rest of this page. The [V2 API reference](https://docs.settlemint.com/docs/api-reference/v2) serves the 3.2 document. A typed client then reports most of the changes below as compile errors: a removed operation, a field that is now required, a removed response field and a renamed path parameter. The changes in [New refusals on existing operations](#new-refusals-on-existing-operations) do not show up at compile time, because they are new error responses on operations whose shape did not change. Read that section whatever your client is built with.

| Change | Affects | Detected at |
| --- | --- | --- |
| [The TypeScript SDK changed its client](#the-typescript-sdk) | Every SDK user | Compile time |
| [The CLI commands are verb-first](#the-cli) | Scripts and agents that call `dalp` | Run time |
| [Error bodies drop `defined`](#error-bodies-drop-defined) | Clients that read `defined` on an error | Run time |
| [187 v2 operations are removed](#removed-v2-operations) | Clients that call one of them | Compile time |
| [Required fields added to v2 requests](#required-fields-added-to-v2-requests) | Freezes, user creation, invitations, organisations | Compile time |
| [v2 response rows changed shape](#v2-response-shapes-that-changed) | Strict response decoders | Compile time |
| [Flat collection keys are refused](#flat-collection-keys-are-refused) | v2 list calls that send `limit`, `offset`, `sortBy`, `sortDirection` or `filters` | Run time |
| [Gas refusals answer `TRANSACTION_QUEUE_FUNDING_REQUIRED`](#gas-refusals) | Token and token-feature writes | Run time |
| [Mint and burn are refused while a corporate action runs](#mint-and-burn-during-a-corporate-action) | Mint and burn callers | Run time |
| [Burns and forced transfers refuse a frozen address](#burns-and-forced-transfers-on-a-frozen-address) | Burn and forced-transfer callers | Run time |
| [A fee recipient change pays the old recipient first](#fee-recipient-changes) | Clients that change a management fee recipient | Run time |
| [Pause and resume answer swapped contract codes](#pause-and-resume-codes) | Clients that branch on `DALP-1109` or `DALP-9059` | Run time |
| [A price with too many decimals is refused](#prices-with-too-many-decimals) | Price writes | Run time |
| [Shipped asset class slugs are reserved](#shipped-asset-class-slugs) | Asset class create and rename | Run time |
| [The original asset families answer new codes](#original-asset-families) | Token creation and factory installation | Run time |
| [Templates must be published before issuance](#template-publication) | Token creation and issuance runs | Run time |
| [v1 writes a maker-checker group protects are refused](#v1-writes-under-maker-checker) | v1 clients in an organisation that protects changes | Run time |
| [Asset document and template deletes answer new codes](#asset-documents) | Document replace and delete, template delete | Run time |
| [Venue event reads hide the counterparty](#trading-venue-reads) | Clients that read venue trades or session states | Run time |
| [Webhook registration replays on the same key](#webhook-registration-replays) | Clients that retry `POST /api/v2/webhooks` | Run time |
| [v1 reads drop wallet and gas fields](#v1-reads-drop-wallet-and-gas-fields) | v1 clients that read a user's `wallet` or an event's gas fields | Compile time |
| [Three v1 operations are removed](#removed-v1-operations) | v1 clients | Run time |
| [v1 writes are refused while maker-checker protects them](#v1-writes-under-maker-checker) | v1 clients that change roles, freezes, transfers or settings | Run time |
| [Changes for clients built against 3.0](#upgrading-from-30) | Clients built against DALP 3.0 | Both |

A client without generated types meets every change in the table as a failing request.

## Client libraries and tools [#client-libraries-and-tools]

### The TypeScript SDK [#the-typescript-sdk]

**What changed.** The 3.2 SDK, `@settlemint/dalp-sdk`, builds its client from the generated route tree:

- You create the client with `createDalpClient({ baseUrl, apiKey })`. 3.1 took `url` and a top-level `organizationId`. 3.2 has no organisation option, because the credential names the organisation: an API key acts in the organisation it was issued for, and a session in its active organisation.
- Routes sit under `dalp.api.*` and take one flat argument object instead of `{ params, query, body }`.
- Token routes name their path value `assetId`, where 3.1 named it `tokenAddress`.
- Helpers that the 3.1 package exported from its root, such as `waitForTransaction`, the auth client and the webhook verifier, move to subpaths such as `@settlemint/dalp-sdk/wait-for-transaction`.
- The `requestValidation` and `responseValidation` options are gone, because the client checks every success response against the route's schema.
- A queue-backed write sends `Prefer: wait=15` unless you set `settlementTimeoutMs`. The 3.1 client sent `Prefer: wait=99` on every write.

**Who is affected.** Every application that imports `@settlemint/dalp-sdk`.

**How to detect it.** Upgrade the package and compile. Each changed call, import and option fails to type-check.

**What to do.** Follow the call-by-call [TypeScript SDK migration guide](https://docs.settlemint.com/docs/api-reference/sdk/migration). Set `settlementTimeoutMs` if your code relied on the longer 99-second wait, and handle the `{ transactionId, status, statusUrl }` handle that a write returns when it has not settled within that wait. [Calling routes](https://docs.settlemint.com/docs/api-reference/sdk/calling-routes) covers the 3.2 client.

### The CLI [#the-cli]

**What changed.** The 3.1 CLI was a hand-written tree of noun-first commands, such as `dalp contacts list`. The 3.2 CLI generates its commands from the v2 API and puts the verb first: `dalp get contacts`. The verb comes from the HTTP method: `get` for GET, `create` for POST, `patch` for PATCH, `replace` for PUT and `delete` for DELETE. Only `login`, `logout`, `whoami`, `config` and `org` stay hand-written. `dalp --mcp` still starts the Model Context Protocol server, but it no longer registers one tool for each command. It offers four tools instead: `search_tools`, `get_tool_details`, `call_read_tool` and `call_write_tool`. `call_read_tool` runs only read commands, which are HTTP GETs, and refuses any other with `Tool is not read-only: <tool name>`. `call_write_tool` runs only the others and refuses a read command with `Tool is read-only: <tool name>`.

**Who is affected.** Shell scripts, CI jobs and AI agents that call `dalp`.

**How to detect it.** A 3.1 command name fails as an unknown command. An agent that calls a command through the wrong tool receives `Tool is not read-only` or `Tool is read-only`.

**What to do.** Run `dalp --help` and rewrite each command in the verb-first form. Point agents at `call_read_tool` for reads and `call_write_tool` for writes. [CLI commands](https://docs.settlemint.com/docs/api-reference/cli/commands) describes the pattern, and [AI agents](https://docs.settlemint.com/docs/api-reference/cli/ai-agents) describes the MCP server.

## Changes to every error response [#changes-to-every-error-response]

### Error bodies drop `defined` [#error-bodies-drop-defined]

**What changed.** A 3.1 error body carried five top-level fields: `defined`, `code`, `status`, `message` and `data`. The 3.2 body carries four: `code`, `status`, `message` and `data`. `defined` is gone from both v1 and v2 error responses. `data` always holds `id`, the `DALP-` identifier of the failure, together with `why`, `fix`, `retryable` and `category`, plus any fields specific to that failure.

**Who is affected.** Clients that branch on `defined` to tell a declared error from an unexpected one.

**How to detect it.** `defined` is missing from every error body.

**What to do.** Identify a failure by `data.id`, decide on a retry from `data.retryable`, and show `data.fix` to the person who has to act. [Errors](https://docs.settlemint.com/docs/api-reference/guides/errors) describes the envelope.

## Removed v2 operations [#removed-v2-operations]

**What changed.** 187 operations that the DALP 3.1 v2 API published are not in the 3.2 v2 API. 145 of them have a 3.2 successor. Most successors fold several narrow operations into one: role grants and revokes become one role-set call, state changes become one `transitions` call, smart wallet operations move under `/custody/wallets`, and statistics move behind one operation with a `metric` parameter. The other 42 have no v2 successor. A v1 operation still serves eight of those, and the other 34 have no replacement. The full list is in [Removed v2 operations and their successors](#removed-v2-operations-and-their-successors).

**Who is affected.** Any client that calls one of the removed operations.

**How to detect it.** A generated client no longer has the operation and fails to compile. A hand-written client receives HTTP 404 with code `ROUTE_NOT_FOUND` and `data.id` `DALP-18235`.

**What to do.** Move each call to the successor the table names, and read the successor's request schema in the API reference, because a successor often takes the old operation's intent as a field, such as `to` on a `transitions` call. Where the table names no successor, drop the call or move it to the v1 operation the table names.

## Required fields added to v2 requests [#required-fields-added-to-v2-requests]

**What changed.** These v2 operations refuse a request that leaves out a field 3.1 did not ask for:

| Operation | Field now required |
| --- | --- |
| `PUT /api/v2/tokens/{assetId}/address-freezes` | `reason` |
| `POST /api/v2/tokens/{assetId}/partial-freezes` | `reason`, for holdings on an EVM network |
| `POST /api/v2/tokens/{assetId}/partial-unfreezes` | `reason` |
| `POST /api/v2/invitations` | `custodyAccountId` |
| `POST /api/v2/invitation-acceptances` | `custodyAccountId` |
| `POST /api/v2/organizations` | `custodyAccountId`. The 3.1 fields `name` and `custody` are refused |
| `POST /api/v2/users` | `providerConfigurationId`, the custody provider configuration for the new user, which `GET /api/v2/custody/provider-configurations` lists |
| `PATCH /api/v2/users/me` | `language`, which is now the only field the body takes |

A freeze or unfreeze `reason` is an object with a `code` and an optional `text`. The code is one of `aml-review`, `sanctions-screening`, `fraud-investigation`, `court-order`, `regulatory-request`, `client-request` or `other`, and `other` needs a `text` of 1 to 500 characters. The platform records the reason in the audit trail beside the freeze. `custodyAccountId` binds the invitation, the acceptance or the new organisation to one exact custody account. `PATCH /api/v2/users/me` sets the person's language. The bodies of `PATCH /api/v2/users/me` and `POST /api/v2/organizations` accept no field beyond those they declare, so a 3.1 body that still carries `onboardingKycVisited`, or `name` and `custody`, is refused with `REQUEST_INVALID`.

**Who is affected.** Clients that freeze or unfreeze holdings, invite people or accept invitations, create organisations or users, or update the signed-in user.

**How to detect it.** A generated client fails to compile without the field, or with a field the 3.2 body does not take. At run time the platform answers HTTP 400 with code `REQUEST_INVALID`, and `data.errors` names the field.

**What to do.** Send the new field and drop the refused ones. For `custodyAccountId`, read the participant's custody accounts first, from `GET /api/v2/participants/{participantId}/custody-accounts`, and pass the one the action should use.

## v2 response shapes that changed [#v2-response-shapes-that-changed]

**What changed.** Some v2 responses changed shape:

- Several list rows became a union that a `family` field tells apart, among them the rows of `GET /api/v2/transaction-requests`, `GET /api/v2/users/me/events` and `GET /api/v2/addons/xvp-settlements`. A field such as `transactionHash` or `createdAt` no longer sits at the top level of the row schema. Every field is still present on a row whose `family` is `evm`. A `GET /api/v2/tokens` row is `{ ref, token }`, and `token._tag`, which is `evm`, `canton` or `deploying`, tells its variants apart.
- User wallet projections, `executorAddress`, `signingAddress` and, on `GET /api/v2/users/me`, `effectiveWallet`, are replaced by collections of the participant's custody accounts, and user asset balances no longer group by one wallet (`byWallet`).
- `dob` leaves the rows of `GET /api/v2/users` and `GET /api/v2/admin/users`. `GET /api/v2/users` still accepts `filter[dob]`. An organisation that records a date of birth declares it as a profile field, which `GET /api/v2/users/{userId}/profile` returns.
- The member list returns a union of the full row and a narrowed row when the request names a `view=summary` or a `fields[user]` projection.
- An asset type template's `featureConfig` is `null` or an array with one attachment for each feature, on read and on create and update. It was an object.
- A queued transaction write that answers `202 Accepted` carries the queue handle, `transactionId`, `status` and `statusUrl`, instead of a copy of the `200` body. Other `202` responses have their own body, which each route's reference documents.
- Some optional response fields are now declared nullable.
- `funding` in the `POST /api/v2/organizations/networks/bundler` response is `funded` or `ask-raised`. It is no longer `unknown`.

**Who is affected.** Clients with strict response types or strict decoders, and clients that send `featureConfig` as an object.

**How to detect it.** A client generated from the 3.2 document fails to compile where it reads a moved field without first narrowing on `family`, or where it reads a removed field.

**What to do.** Narrow on `family`, or on `token._tag` for a token row, before reading an EVM row's fields. Read custody accounts instead of the removed wallet fields. Send `featureConfig` in the attachment form the API reference shows. On a `202`, poll `statusUrl` until the transaction settles instead of reading the result from the body.

## New refusals on existing operations [#new-refusals-on-existing-operations]

These operations keep their shape in 3.2 but refuse requests they used to accept, or answer a refusal with a different code. A typed client does not see them at compile time.

### Flat collection keys are refused [#flat-collection-keys-are-refused]

**What changed.** v2 list operations that take the collection parameters `page`, `sort` and `filter` refuse the flat query keys `limit`, `offset`, `sortBy`, `sortDirection` and `filters`. 3.1 accepted them and converted them to the canonical form. A list that declares its own flat `limit`, with `offset` or `cursor`, such as `GET /api/v2/transaction-requests`, accepts the keys it declares. The platform answers HTTP 400 with code `REQUEST_INVALID` and `data.id` `DALP-14261`, and `data.errors` names the key: `Collection query key "limit" is not supported: send sort, page[offset], page[limit], and filter[<field>]`. The refusal is not retryable.

**Who is affected.** Any client that pages, sorts or filters such a list with the flat keys.

**How to detect it.** A list call answers HTTP 400 where it used to answer 200.

**What to do.** Send `page[limit]`, `page[offset]`, `sort` and `filter[<field>]`, as [Pagination](https://docs.settlemint.com/docs/api-reference/guides/pagination) describes. Correct the request before you send it again, because an unchanged retry fails the same way.

### Gas refusals [#gas-refusals]

**What changed.** When the platform refuses a token or token-feature write because the account that pays for it cannot pay the gas, the operation answers HTTP 400 with code `TRANSACTION_QUEUE_FUNDING_REQUIRED` and `data.id` `DALP-14062`. This covers a direct token or token-feature write, a token role change, a token creation or a token price update that waits for its result, and the coordinated corporate-action steps: preview, confirm, abort and leg release. `data.refusal` is `FundingRequired`, and `data.transactionId` names the transaction request when the platform recorded one. The new refusal is not retryable. A step whose smart wallet pays its own gas and holds too little answers HTTP 422 `TRANSACTION_QUEUE_SMART_WALLET_GAS_REQUIRED` (`DALP-14034`), with `smartWalletAddress` and `shortfallWei` in `data`.

**Who is affected.** Clients that write to tokens or token features, change token roles, create tokens, update prices or run coordinated corporate actions, and that handle a gas shortfall.

**How to detect it.** The write answers HTTP 400 with `data.refusal` set to `FundingRequired`.

**What to do.** Fund the paying account, then send the write again. If the retry answers `TRANSACTION_QUEUE_DUPLICATE_SETTLED` (`DALP-14066`), the idempotency key already names the refused transaction: read that transaction's outcome and send the write under a new `Idempotency-Key`. Do not retry this code automatically. [Error handling](https://docs.settlemint.com/docs/api-reference/errors/error-handling#funding-and-custody-failures) covers recovery.

### Bundler wallet without a fee quote [#bundler-wallet-without-a-fee-quote]

**What changed.** `POST /api/v2/organizations/networks/bundler` sizes the bundler wallet's funding request from the network's live fee quote. When the network has no fresh fee quote, it answers HTTP 503 with `data.id` `DALP-12250`, a retryable dependency failure. When the platform cannot record the funding request, it answers a retryable failure too. 3.1 answered both cases with HTTP 200 and `funding` set to `unknown`.

**Who is affected.** Clients that create or repair a bundler wallet and treat `funding: "unknown"` as a success.

**How to detect it.** The call answers HTTP 503 where it used to answer 200.

**What to do.** Retry the call later. The answer is retryable, and the call reuses the bundler wallet that exists.

### Mint and burn during a corporate action [#mint-and-burn-during-a-corporate-action]

**What changed.** A mint or a burn on an asset is refused while a corporate action run is in flight on the same asset. A run is in flight from the moment it starts until it completes or someone aborts it. The platform answers HTTP 409 with code `CORPORATE_ACTION_IN_FLIGHT` and `data.id` `DALP-12067`, and `data.corporateActionId` names the run that holds the asset.

**Who is affected.** Every client that mints or burns, including one whose own operator did not start the corporate action.

**How to detect it.** The mint or burn answers HTTP 409 with `CORPORATE_ACTION_IN_FLIGHT`.

**What to do.** Wait until the run named in `data.corporateActionId` completes, or abort it, then send the mint or burn again. [Corporate actions](https://docs.settlemint.com/docs/api-reference/guides/corporate-actions) describes the run.

### Burns and forced transfers on a frozen address [#burns-and-forced-transfers-on-a-frozen-address]

**What changed.** An asset on the DALP 3.2 token contract refuses a burn from an address frozen as a whole, with `DALP-1076` ("Sender address frozen"), and a forced transfer into one, with `DALP-1074` ("Recipient address frozen"). A request that names several holders fails as a whole when one of them is frozen. 3.1 burned from a frozen address and delivered a forced transfer into one. A freeze of part of a balance still stops neither: the write releases the frozen units it needs. An asset issued from an instrument template moves to the DALP 3.2 token contract when its organisation runs [System updates](https://docs.settlemint.com/docs/console/organisation-settings/system-updates). An asset of the seven original asset families, such as a bond or an equity from its type-specific factory, keeps the 3.1 behaviour.

**Who is affected.** Clients that call `POST /api/v2/tokens/{assetId}/burns` or `POST /api/v2/tokens/{assetId}/forced-transfers` for a holder whose address may be frozen.

**How to detect it.** The Platform API does not check the address freeze before it queues the write, so the request still answers `202 Accepted`. Its transaction then ends `FAILED`, with `contractError.id` `DALP-1076` or `DALP-1074`. A request sent with `Prefer: wait` answers HTTP 422 `CONTRACT_ERROR` with that code in `data.id`.

**What to do.** Read `data.holder.balance.isFrozen` from `GET /api/v2/tokens/{assetId}/holder-balances?holderAddress=<address>` before you burn from or force a transfer into an address. Lift the freeze first with `PUT /api/v2/tokens/{assetId}/address-freezes`, sending `userAddress` and `freeze: false`. To burn a frozen holder's units and keep the freeze, move them with a forced transfer to an eligible wallet, which a freeze on the sender does not stop, and burn them there.

### Fee recipient changes [#fee-recipient-changes]

**What changed.** On the DALP 3.2 management fee feature, a recipient change through `PATCH /api/v2/tokens/{assetId}/features/aum-fee` first pays the fees accrued so far to the old recipient, as a rate change already did. It fails, and changes nothing, while the asset refuses that payment: the asset is halted (`DALP-1109`), the old recipient's address is frozen (`DALP-1074`), or the old recipient no longer passes the asset's compliance rules (`DALP-1110`). 3.1 switched the recipient without paying, so the new recipient's first collection included the period the old recipient earned. A management fee moves to the 3.2 feature when its organisation runs [System updates](https://docs.settlemint.com/docs/console/organisation-settings/system-updates).

**Who is affected.** Clients that change a management fee recipient.

**How to detect it.** The request still answers `202 Accepted`, and its transaction ends `FAILED` with one of those codes in `contractError.id`, or, with `Prefer: wait`, HTTP 422 `CONTRACT_ERROR` with the code in `data.id`. A successful change records a fee payment to the old recipient.

**What to do.** Resume the asset, or unfreeze or re-verify the old recipient, before you change the recipient. Reconcile the payment to the old recipient that the change makes.

### Pause and resume codes [#pause-and-resume-codes]

**What changed.** The DALP 3.2 token contract refuses a halt of an asset that is already halted with `DALP-1109`, and a resume of an active asset with `DALP-9059`. Every other token contract answers the reverse. `PATCH /api/v2/tokens/{assetId}/pause-state` compares the request with the indexed pause state and refuses a match with `DALP-9488`. A contract code reaches a client when the chain holds a state the platform has not indexed yet, such as a second halt sent before the first is indexed. It arrives as `contractError.id` on the failed transaction, or in `data.id` of an HTTP 422 `CONTRACT_ERROR` with `Prefer: wait`.

**Who is affected.** Clients that branch on `DALP-1109` or `DALP-9059` after a halt or a resume.

**How to detect it.** A halt answers `DALP-1109` where it used to answer `DALP-9059`, or a resume the reverse.

**What to do.** After a halt or a resume, read `DALP-9488`, `DALP-1109` and `DALP-9059` as "the asset already has the state you asked for", whichever action you sent.

### v1 writes under maker-checker [#v1-writes-under-maker-checker]

**What changed.** When an organisation protects a group of changes with [maker-checker](https://docs.settlemint.com/docs/concepts/custody-and-signing/maker-checker), a v2 write in that group is held for a second user's approval. The v1 API cannot hold a request, so a v1 write whose v2 route the protected group would hold is refused before anything runs. The refusal is HTTP 403 with the v1 code `FORBIDDEN`, and `data.id` is the id that route already answers for a refused caller: `DALP-9485` on token routes, `DALP-12252` on platform routes and `DALP-0003` on identity, compliance and user routes. Four v1 writes had no 403 in 3.1 and gain one in 3.2, answering `DALP-12252`: `POST /api/v1/external-token/register`, `POST /api/v1/kyc-profile-versions/{versionId}/request-update`, `POST /api/v1/user/create` and `POST /api/v1/user/admin/session/revoke`. The refusal is not retryable.

**Who is affected.** v1 clients in an organisation that protects a group, such as Token administration or System administration.

**How to detect it.** A v1 write answers HTTP 403 whose `message` says the organisation holds the change for a second user's approval.

**What to do.** Send the change to the v2 route that `data.fix` names. It answers `202` and holds the change until a second user approves it.

### Prices with too many decimals [#prices-with-too-many-decimals]

**What changed.** A price write that holds more decimal places than the price feed stores is refused. This covers a token price update, a price feed submission, and the initial price of a token creation. The platform answers HTTP 400 with code `FEED_PRICE_NOT_REPRESENTABLE` and `data.id` `DALP-12245`, and the message names the price and the feed's decimals. 3.1 accepted the value and cut the extra digits off, rounding toward zero.

**Who is affected.** Clients that send prices with more precision than the feed stores.

**How to detect it.** The price write answers HTTP 400 with `FEED_PRICE_NOT_REPRESENTABLE`.

**What to do.** Round or format the price to the feed's decimals before you send it. The refusal is not retryable unchanged.

### Shipped asset class slugs [#shipped-asset-class-slugs]

**What changed.** Creating a custom asset class, or renaming one, onto the slug of an asset class that DALP ships is refused. The shipped slugs are `fixed-income`, `equity`, `funds`, `cash`, `real-assets`, `structured`, `derivatives`, `yield-instruments` and `digital-assets`. The platform answers HTTP 409 with code `SETTINGS_TEMPLATE_NAME_ALREADY_EXISTS`, `data.id` `DALP-0463` and the message `The slug "<slug>" belongs to a system asset class. Choose a different name.`

The upgrade also resolves an organisation's own class that already uses the slug of a shipped class. Each shipped class allows these base types:

| Shipped class | Allowed base types |
| --- | --- |
| `fixed-income` | `bond` |
| `equity` | `equity` |
| `funds` | `fund` |
| `cash` | `stablecoin`, `deposit` |
| `real-assets` | `real-estate`, `precious-metal` |
| `structured` | `bond`, `fund` |
| `derivatives`, new in 3.2 | `equity` |
| `yield-instruments`, new in 3.2 | `equity` |
| `digital-assets` | every base type |

If every template in the organisation's own class has a base type the shipped class allows, the shipped class adopts its templates, and the organisation's own class row is deleted, so its identifier no longer exists. Otherwise the class stays the organisation's own and moves to the slug `<old slug>-<first eight letters and digits of its identifier, in lower case>`, with its name, identifier and templates unchanged. For `derivatives` and `yield-instruments`, a template whose own class row was already deleted follows the same split: an `equity` template joins the shipped class, and any other template moves to `<old slug>-custom`.

**Who is affected.** Clients that create or rename asset classes, and clients that look up or store an organisation's own class under the slug of a shipped class.

**How to detect it.** A create or rename answers HTTP 409 with `DALP-0463`. After the upgrade, a lookup by the old slug returns the shipped class, or a class identifier stored before the upgrade no longer resolves.

**What to do.** Choose another slug. Key asset classes by identifier, and read the class list again after the upgrade.

### Original asset families [#original-asset-families]

**What changed.** The seven asset families of the original catalogue, `bond`, `equity`, `fund`, `stablecoin`, `deposit`, `real-estate` and `precious-metal`, cannot be created or installed unless the deployment turns legacy asset creation on, and it is off by default. The 3.1.19 patch release introduced this refusal, and 3.2 answers it with different codes. A v2 token creation of one of these types answers HTTP 422 with code `TOKEN_CREATE_ASSET_FAMILY_DEPRECATED` (`DALP-12075`), where 3.1 answered HTTP 400 with `DALP-9103`. A v2 factory installation for one of them answers HTTP 422 with code `PLATFORM_FACTORY_TYPE_UNUSABLE` (`DALP-14339`), where 3.1 answered with `DALP-9104`. The v1 token creation answers HTTP 422 with the v1 code `INPUT_VALIDATION_FAILED` and `data.id` `DALP-9243`. None is retryable. The refusal applies to new creations and factory installations, and the platform removes no factory that a system already has. 3.0 had no such refusal.

**Who is affected.** Clients that still create tokens of these seven types, and clients that branch on the 3.1 status or identifiers.

**How to detect it.** Read `data.features.legacyAssetCreation` from `GET /api/v2/settings/public-config`. When it is `false`, a create or install of those seven families is refused.

**What to do.** Create the asset from a current instrument template, or ask the platform operator to turn legacy asset creation on, as [Upgrade a deployment to DALP 3.2](https://docs.settlemint.com/docs/deployment/upgrade-to-3-2#decide-on-legacy-asset-creation) describes. Match the 3.2 `data.id` values above. A client that branches on `code` replaces the 3.1 codes `TOKEN_CREATE_TYPE_DEPRECATED` and `TOKEN_FACTORY_TYPE_DEPRECATED`.

### Template publication [#template-publication]

**What changed.** An organisation issues only from instrument templates and structures that are published. The templates an organisation creates itself count as published. Of the templates that DALP ships, Equity, Bond and Stablecoin start published in every organisation, and every other one starts unpublished. A v2 token creation from an unpublished template answers HTTP 409 with code `TOKEN_CREATE_TEMPLATE_UNPUBLISHED` (`DALP-14019`). An issuance run answers HTTP 409 with `TOKEN_ISSUANCE_RUN_TEMPLATE_UNPUBLISHED` (`DALP-14020`) for an unpublished member template, or `TOKEN_ISSUANCE_RUN_STRUCTURE_UNPUBLISHED` (`DALP-14024`) for an unpublished structure. The v1 token creation answers HTTP 422 with the v1 code `INPUT_VALIDATION_FAILED` and `data.id` `DALP-0316`. None is retryable unchanged.

**Who is affected.** Clients that create tokens or start issuance runs from templates other than Equity, Bond and Stablecoin.

**How to detect it.** The template's `isPublished` field is `false`.

**What to do.** Publish the template with `PUT /api/v2/settings/asset-type-templates/{assetTypeTemplateId}/publication`, or ask an organisation owner to publish it in the Console, then send the request again.

### Asset documents [#asset-documents]

**What changed.** A document confirm whose `replaceGroupId` names a document group of another document type answers HTTP 404 with `DALP-0322`, where it used to add a version of the new type to that group. A document delete by a wallet without the governance role answers HTTP 403 with `DALP-9485` whether or not the document exists, where it used to answer 404 for a document it could not find. Deleting an instrument template that tokens were issued from answers HTTP 409 with `DALP-181131`, where it used to answer 500.

**Who is affected.** Clients that replace asset documents or delete them, and clients that delete instrument templates.

**How to detect it.** A response that carries one of the `data.id` values this change names.

**What to do.** Replace a document only within a group of the same type. Treat a 403 on delete as a missing role, not a missing document. A template that tokens were issued from cannot be deleted.

### v1 KYC document uploads and downloads [#v1-kyc-document-uploads-and-downloads]

**What changed.** The v1 KYC document confirm validates the uploaded file (declared size, a 25 MiB bound and the file's real type) and stores it encrypted, as the v2 upload does. 3.1 stored it unencrypted and unvalidated. A confirm that fails validation answers a refusal and deletes the uploaded object, so request a new upload link and send the file again. The v1 and v2 document download calls always return a relative `/api/v2/` path that needs your credential. 3.1 returned an absolute object-storage URL, usable by anyone who held it, for a document that the v1 upload had stored unencrypted. The platform now encrypts those documents in the background. A presigned upload that is never confirmed is deleted 30 minutes after the link was issued.

**Who is affected.** Clients that upload KYC documents through the v1 presigned upload, and clients that fetch a KYC document from the `downloadUrl` it returns.

**How to detect it.** A `downloadUrl` that starts with `/api/v2/` where it used to start with `https://`, and a confirm that answers a refusal for a file whose type differs from the declared one.

**What to do.** Send your session or API key when you fetch `downloadUrl`, and resolve a relative path against your DALP base URL. Declare the file's real size and type on the confirm. Prefer the v2 upload, which sends the file to the platform and never leaves it unencrypted in object storage.

## Trading venue reads [#trading-venue-reads]

**What changed.** `GET /api/v2/users/me/events` and `GET /api/v2/tokens/{assetId}/events`, and the v1 token events, name only the caller's own side of a trade a venue settled. In the Swap row, `swap.buyer`, `swap.seller`, and a transfer's `from` and `to` can be `null`, and the decoded `buyer`, `seller`, `buyOrderHash` and `sellOrderHash` values and `involved` follow the same rule. A venue operator still reads both sides. An instrument's `sessionState`, and a calendar occurrence's `appliedState`, can be `trade-at-last`, and calendar days, exceptions and venue calendars accept an optional `tradeAtLastTime`.

**Who is affected.** Clients that read the counterparty of their own trade from the event reads, and clients that list session states.

**How to detect it.** A null counterparty on a venue trade, or a session state the client does not know.

**What to do.** Read the counterparty from the venue's operator reads, with an operator's credentials. Treat an unknown session state as not tradable rather than open.

## Webhook registration replays [#webhook-registration-replays]

**What changed.** `POST /api/v2/webhooks` treats a retry with the same `Idempotency-Key` and the same body as a replay. It returns the endpoint the first request registered, with `signingSecret` set to `null`, and registers no second endpoint. The operation returns the key it used in the `Idempotency-Key` response header, including a key the platform generated because the request sent none. A reused key with a different body, a key whose endpoint was deleted, or a key whose registration never completed answers HTTP 409 `WEBHOOK_IDEMPOTENCY_KEY_REUSED` (`DALP-0537`), which is not retryable. A retry while the first request is still registering answers HTTP 409 `WEBHOOK_CREATE_IN_PROGRESS` (`DALP-0538`), which is retryable.

Every write under `/api/v2/webhooks`, and `POST /api/v2/webhook-receipts`, no longer declares a `202` response in the contract: each finishes before it responds and returns `200`.

**Who is affected.** Clients that retry webhook registration, and clients that expect the signing secret on every successful registration response.

**How to detect it.** A replayed registration returns `signingSecret: null`.

**What to do.** Store the signing secret from the first successful response, because a replay does not return it. Keep the `Idempotency-Key` response header so that a client that lost the response can replay it. On `WEBHOOK_CREATE_IN_PROGRESS`, send the same request again after a short wait. On `WEBHOOK_IDEMPOTENCY_KEY_REUSED`, register under a new key. If the secret is lost, rotate it, as [Webhooks](https://docs.settlemint.com/docs/api-reference/guides/webhooks#rotate-the-signing-secret) describes.

## Removed v1 operations [#removed-v1-operations]

**What changed.** 3.2 removes three v1 operations without the 90-day deprecation notice that [Versioning and deprecation](https://docs.settlemint.com/docs/api-reference/guides/versioning-and-deprecation) describes. The rest of the v1 structure stays, apart from the fields that [v1 reads drop wallet and gas fields](#v1-reads-drop-wallet-and-gas-fields) lists:

| 3.1 v1 operation | 3.2 replacement |
| --- | --- |
| `GET /api/v1/user/by-wallet/{wallet}` | `GET /api/v2/users`, filtered by wallet. A wallet can match more than one user. |
| `POST /api/v1/user/create-wallet` | `POST /api/v2/custody/accounts/lifecycle` |
| `PATCH /api/v1/user/me` | None. The onboarding flag it set no longer exists, and `PATCH /api/v2/users/me` sets only the language. |

**Who is affected.** v1 clients that call one of the three.

**How to detect it.** The call answers HTTP 404 with the body `{"code":"NOT_FOUND","status":404,"message":"The request could not be completed"}` and the content type `text/plain`. The body has no `data` object.

**What to do.** Move the call to the v2 replacement. v1 error bodies change as described in [Error bodies drop `defined`](#error-bodies-drop-defined).

## v1 reads drop wallet and gas fields [#v1-reads-drop-wallet-and-gas-fields]

**What changed.** The v1 user reads no longer return the user's single-wallet fields `wallet`, `executorAddress` and `signingAddress`: `GET /api/v1/user/me`, `GET /api/v1/user/by-id/{userId}`, `GET /api/v1/user/list`, `GET /api/v1/user/list/admins`, `GET /api/v1/user/search`, the user results of `GET /api/v1/search`, and the response of `POST /api/v1/user/create`. `GET /api/v1/user/me` also no longer returns `effectiveWallet`. A user can hold more than one custody account, so one wallet field cannot describe it. `GET /api/v1/user/events` no longer returns `gasPrice` or `gasUsed`, because the platform does not index the gas a transaction used.

**Who is affected.** v1 clients that read a user's wallet from these responses, or the gas fields of a user event.

**How to detect it.** A client generated from the 3.2 document fails to compile where it reads the fields. At run time the fields are absent, with no error.

**What to do.** Read the user's custody accounts from `GET /api/v2/participants/{participantId}/custody-accounts`, with the `participantId` that `GET /api/v1/user/by-id/{userId}` and `GET /api/v1/user/list` return. Treat `gasPrice` and `gasUsed` as absent.

## v1 writes under maker-checker [#v1-writes-under-maker-checker-1]

**What changed.** A v1 client cannot read the `202` answer that holds a request for a second approver. A v1 write whose v2 route an organisation holds under maker-checker, the control in which a second approver must approve a change before it runs, is therefore refused before anything runs. The refusal is the `403` that the v1 route already declares for a caller who lacks access, with a message that names the protection group and a `data.fix` that names the v2 route to send the change to. A v1 write whose v2 route is never held, such as a mint, runs as before.

**Who is affected.** v1 clients that change roles, freeze addresses, force transfers or edit settings in an organisation that protects the matching group.

**How to detect it.** The `403` carries a message that names the protection group.

**What to do.** Send the change to the v2 route that `data.fix` names. [Maker-checker approval](https://docs.settlemint.com/docs/concepts/custody-and-signing/maker-checker) describes the groups and the second approval.

## Upgrading from 3.0 [#upgrading-from-30]

A client built against DALP 3.0 needs every change on this page and nothing more. Every v1 and v2 operation that 3.0 published is still in 3.1, so 3.1 removed nothing that a 3.0 client calls. The refusal of the [original asset families](#original-asset-families) arrived in the 3.1.19 patch release, so a 3.0 client meets it for the first time on this upgrade.

## Removed v2 operations and their successors [#removed-v2-operations-and-their-successors]

Each row is an operation that the DALP 3.1 v2 API published and the 3.2 v2 API does not. Paths are relative to `/api/v2`. Path parameters keep their position when a successor renames them, such as `{tokenAddress}` to `{assetId}`.

| 3.1 operation | 3.2 operation | Note |
| --- | --- | --- |
| `GET /actions` | None | No 3.2 operation. |
| `POST /addons/token-sale-activations` | `POST /addons/token-sales/{saleAddress}/transitions` | Send the target state in `to`. |
| `POST /addons/token-sale-closures` | `POST /addons/token-sales/{saleAddress}/transitions` | Send the target state in `to`. |
| `POST /addons/token-sale-finalizations` | `POST /addons/token-sales/{saleAddress}/transitions` | Send the target state in `to`. |
| `POST /addons/token-sale-fund-withdrawals` | `POST /addons/token-sales/{saleAddress}/fund-withdrawals` |  |
| `DELETE /addons/token-sale-pauses` | `POST /addons/token-sales/{saleAddress}/transitions` | Send the target state in `to`. |
| `POST /addons/token-sale-pauses` | `POST /addons/token-sales/{saleAddress}/transitions` | Send the target state in `to`. |
| `DELETE /addons/token-sale-payment-currencies` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `POST /addons/token-sale-payment-currencies` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `DELETE /addons/token-sale-presale-whitelist-entries` | `DELETE /addons/token-sales/{saleAddress}/presale-whitelist-entries` |  |
| `POST /addons/token-sale-presale-whitelist-entries` | `POST /addons/token-sales/{saleAddress}/presale-whitelist-entries` |  |
| `PATCH /addons/token-sale-purchase-limits` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `POST /addons/token-sale-purchases` | `POST /addons/token-sales/{saleAddress}/purchases` |  |
| `POST /addons/token-sale-refund-claims` | `POST /addons/token-sales/{saleAddress}/refund-claims` |  |
| `PATCH /addons/token-sale-soft-caps` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `POST /addons/token-sale-term-acknowledgements` | `POST /addons/token-sales/{saleAddress}/term-acknowledgements` |  |
| `PATCH /addons/token-sale-terms` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `POST /addons/token-sale-token-withdrawals` | `POST /addons/token-sales/{saleAddress}/token-withdrawals` |  |
| `POST /addons/token-sale-unsold-token-withdrawals` | `POST /addons/token-sales/{saleAddress}/unsold-token-withdrawals` |  |
| `PATCH /addons/token-sale-vesting-configurations` | `POST /addons/token-sales` | Set at sale creation. No later change. |
| `DELETE /addons/xvp-approvals` | `DELETE /addons/xvp-settlements/{settlementAddress}/approvals` |  |
| `POST /addons/xvp-approvals` | `POST /addons/xvp-settlements/{settlementAddress}/approvals` |  |
| `DELETE /addons/xvp-cancellation-requests` | None | No v2 operation. The v1 operation `PUT /api/v1/xvp/withdraw-cancel` serves it. |
| `POST /addons/xvp-cancellation-requests` | `POST /addons/xvp-settlements/{settlementAddress}/cancellation-requests` |  |
| `POST /addons/xvp-executions` | `POST /addons/xvp-settlements/{settlementAddress}/executions` |  |
| `POST /addons/xvp-expiry-withdrawals` | `POST /addons/xvp-settlements/{settlementAddress}/expiry-withdrawals` |  |
| `POST /addons/xvp-secret-decryptions` | `POST /addons/xvp-settlements/{settlementAddress}/secret-decryptions` |  |
| `POST /addons/xvp-secret-revelations` | `POST /addons/xvp-settlements/{settlementAddress}/secret-revelations` |  |
| `POST /addons/xvp-secrets` | `POST /addons/xvp-settlements/{settlementAddress}/secrets` |  |
| `GET /admin/custody/{organizationId}` | None | Replaced by custody provider configurations under `/api/v2/admin/custody/provider-configurations`. |
| `DELETE /admin/custody/{organizationId}/credentials` | None | Replaced by custody provider configurations under `/api/v2/admin/custody/provider-configurations`. |
| `POST /admin/organizations/{id}/archive` | `POST /admin/organizations/{id}/transitions` | Send the target state in `to`. |
| `POST /admin/organizations/{id}/restore` | `POST /admin/organizations/{id}/transitions` | Send the target state in `to`. |
| `GET /blockchain-monitoring/service-health-metrics` | None | No 3.2 operation. |
| `POST /compliance/providers/{providerId}/cancel-secret-rotation` | `DELETE /compliance/providers/{providerId}/secret-rotations/pending` |  |
| `POST /compliance/providers/{providerId}/pause` | `POST /compliance/providers/{providerId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/promote-secret` | `POST /compliance/providers/{providerId}/secret-rotations/promotions` |  |
| `POST /compliance/providers/{providerId}/resume` | `POST /compliance/providers/{providerId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/retry-provisioning` | None | No 3.2 operation. |
| `POST /compliance/providers/{providerId}/revoke` | `POST /compliance/providers/{providerId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/rotate-secret` | `POST /compliance/providers/{providerId}/secret-rotations` |  |
| `POST /compliance/providers/{providerId}/webhooks/{webhookId}/pause` | `POST /compliance/providers/{providerId}/webhooks/{webhookId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/webhooks/{webhookId}/reactivate` | `POST /compliance/providers/{providerId}/webhooks/{webhookId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/webhooks/{webhookId}/resume` | `POST /compliance/providers/{providerId}/webhooks/{webhookId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/webhooks/{webhookId}/revoke` | `POST /compliance/providers/{providerId}/webhooks/{webhookId}/transitions` | Send the target state in `to`. |
| `POST /compliance/providers/{providerId}/webhooks/{webhookId}/rotate-secret` | `POST /compliance/providers/{providerId}/webhooks/{webhookId}/secret-rotations` |  |
| `GET /custody` | None | Replaced by custody provider configurations under `/api/v2/admin/custody/provider-configurations`. |
| `PUT /custody/credentials` | None | Replaced by custody provider configurations under `/api/v2/admin/custody/provider-configurations`. |
| `POST /custody/test-credentials` | None | Replaced by custody provider configurations under `/api/v2/admin/custody/provider-configurations`. |
| `POST /kyc-profile-versions/{versionId}/approvals` | `POST /kyc-profile-versions/{versionId}/decisions` | Send `decision: approve`. |
| `POST /kyc-profile-versions/{versionId}/rejections` | `POST /kyc-profile-versions/{versionId}/decisions` | Send `decision: reject` with a reason. |
| `GET /monitoring/api/endpoint-metrics` | None | No 3.2 operation. |
| `GET /monitoring/api/request-metrics/summary` | None | No 3.2 operation. |
| `GET /monitoring/api/request-metrics/timeline` | None | No 3.2 operation. |
| `GET /monitoring/api/request-metrics/top-errors` | None | No 3.2 operation. |
| `GET /participants/{participantId}/smart-wallet` | `GET /participants/{participantId}/custody-accounts` | Read each account record. |
| `GET /platform-status/data-freshness` | `GET /platform-status` | All panels in one read. |
| `GET /platform-status/platform-api` | `GET /platform-status` | All panels in one read. |
| `GET /platform-status/snapshot` | None | Not in the published 3.2 contract. |
| `GET /platform-status/stat-cards` | `GET /platform-status` | All panels in one read. |
| `GET /platform-status/transactions` | `GET /platform-status` | All panels in one read. |
| `GET /platform-status/workflows` | `GET /platform-status` | All panels in one read. |
| `PUT /settings/asset-type-templates/{id}/publish` | `PUT /settings/asset-type-templates/{assetTypeTemplateId}/publication` | Send `{"published": true}`. |
| `GET /smart-wallets` | `GET /custody/wallets` |  |
| `POST /smart-wallets` | `POST /custody/wallets` |  |
| `GET /smart-wallets/{address}` | `GET /custody/wallets/{walletId}` | Keyed by wallet id, not address. |
| `PATCH /smart-wallets/{address}` | `PATCH /custody/wallets/{walletId}` | Keyed by wallet id, not address. |
| `GET /smart-wallets/{address}/approvals` | `GET /custody/wallets/{walletId}/approvals` | Keyed by wallet id, not address. |
| `POST /smart-wallets/{address}/approvals` | `POST /custody/wallets/{walletId}/approvals` | Keyed by wallet id, not address. |
| `GET /smart-wallets/{address}/approvals/{userOpHash}` | `GET /custody/approvals/{approvalId}` |  |
| `POST /smart-wallets/{address}/approvals/{userOpHash}/sign` | `POST /custody/approvals/{approvalId}/signatures` |  |
| `GET /smart-wallets/{address}/gas-status` | `GET /custody/wallets/{walletId}/gas` | Keyed by wallet id, not address. |
| `POST /smart-wallets/{address}/modules` | `POST /custody/wallets/{walletId}/mutations` | One operation for each wallet change. |
| `DELETE /smart-wallets/{address}/modules/{moduleAddress}` | `POST /custody/wallets/{walletId}/mutations` | One operation for each wallet change. |
| `GET /smart-wallets/{address}/signers` | `GET /custody/wallets/{walletId}/signers` | Keyed by wallet id, not address. |
| `POST /smart-wallets/{address}/signers` | `POST /custody/wallets/{walletId}/mutations` | One operation for each wallet change. |
| `DELETE /smart-wallets/{address}/signers/{signer}` | `POST /custody/wallets/{walletId}/mutations` | One operation for each wallet change. |
| `PUT /smart-wallets/{address}/threshold` | `POST /custody/wallets/{walletId}/mutations` | One operation for each wallet change. |
| `GET /smart-wallets/custody/gas-balance` | None | Not in the published 3.2 contract. |
| `DELETE /system/accounts/{address}/role-grants` | `POST /system/role-sets` | One call grants and revokes. |
| `POST /system/accounts/{address}/role-grants` | `POST /system/role-sets` | One call grants and revokes. |
| `GET /system/feeds/{feedAddress}/config` | `GET /system/feeds/{feedAddress}/configuration` |  |
| `GET /system/feeds/{feedAddress}/nonce/{issuerIdentity}` | None | No 3.2 operation. |
| `GET /system/feeds/{feedAddress}/round/{roundId}` | None | No 3.2 operation. |
| `GET /system/feeds/{feedAddress}/staleness` | None | No 3.2 operation. |
| `POST /system/feeds/{feedAddress}/submit` | `POST /system/feeds/{feedAddress}/submissions` |  |
| `GET /system/feeds/adapters` | None | No 3.2 operation. |
| `POST /system/feeds/adapters/create` | `POST /system/feeds/adapters` |  |
| `GET /system/feeds/issuer-signed` | None | No 3.2 operation. |
| `POST /system/feeds/issuer-signed/create` | `POST /system/feeds/issuer-signed` |  |
| `POST /system/feeds/register-external` | `POST /system/feeds/external-registrations` |  |
| `DELETE /system/feeds/remove` | `DELETE /system/feeds/registrations` |  |
| `PUT /system/feeds/replace` | `PUT /system/feeds/registrations` |  |
| `GET /system/feeds/resolve` | `GET /system/feeds/resolutions` |  |
| `GET /system/migration/{migrationId}/stream` | `GET /system/migrations/{migrationId}/stream` |  |
| `GET /system/migration/active` | `GET /system/migrations/active` |  |
| `GET /system/migration/compare` | `GET /system/migration-comparison` |  |
| `POST /system/migration/start` | `POST /system/migrations` |  |
| `POST /system/participants/role-grants` | `POST /system/role-sets` | One call grants and revokes. |
| `POST /system/participants/role-revocations` | `POST /system/role-sets` | One call grants and revokes. |
| `PUT /system/refund-splitter/bps` | `PATCH /system/refund-splitter` |  |
| `POST /system/refund-splitter/recover-erc20` | None | No 3.2 operation. |
| `POST /system/refund-splitter/recover-native` | None | No 3.2 operation. |
| `PUT /system/refund-splitter/sponsorship` | None | No 3.2 operation. |
| `GET /system/refund-splitter/status` | `GET /system/refund-splitter` |  |
| `GET /system/refund-splitter/thresholds` | `GET /system/refund-splitter` |  |
| `PUT /system/refund-splitter/thresholds` | `PATCH /system/refund-splitter` |  |
| `GET /system/stats/asset-activity-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/asset-activity-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/asset-lifecycle-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/asset-lifecycle-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/assets` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/claim-stat-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/claim-stat-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/claim-stat-snapshots/current` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/country-asset-count` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/identity-count` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/identity-stat-timeseries` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/identity-stat-timeseries/presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/portfolio-breakdowns` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/portfolio-stat-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/portfolio-stat-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/system-value-histories` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/system-value-histories/presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/topic-scheme-claims-coverage` | None | No v2 operation. The v1 operation `GET /api/v1/system/stats/topic-scheme-claims-coverage` serves it. |
| `GET /system/stats/topic-scheme-stat-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/topic-scheme-stat-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/topic-scheme-stat-snapshots/current` | None | No v2 operation. The v1 operation `GET /api/v1/system/stats/topic-schemes-stats-state` serves it. |
| `GET /system/stats/transaction-count` | None | No v2 operation. The v1 operation `GET /api/v1/system/stats/transaction-count` serves it. |
| `GET /system/stats/transaction-history` | None | No v2 operation. The v1 operation `GET /api/v1/system/stats/transaction-history` serves it. |
| `GET /system/stats/trusted-issuer-stat-range-presets/{preset}` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/trusted-issuer-stat-ranges` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/trusted-issuer-stat-snapshots/current` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /system/stats/value` | `GET /system/stats/{metric}` | One statistic per `metric`. |
| `GET /tokens/{tokenAddress}/external-transaction-fee/collection-events` | None | No 3.2 operation. |
| `PATCH /tokens/{tokenAddress}/features/aum-fee/bps` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/aum-fee/recipient` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/conversion-minter/window` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/external-transaction-fee/amounts` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/external-transaction-fee/recipient` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/external-transaction-fee/token` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/fixed-treasury-yield/treasury` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/maturity-redemption/treasury` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/transaction-fee-accounting/rates` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/transaction-fee-accounting/recipient` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/transaction-fee/rates` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `PATCH /tokens/{tokenAddress}/features/transaction-fee/recipient` | `PATCH /tokens/{assetId}/features/{name}` | Send only the settings that change. |
| `POST /tokens/{tokenAddress}/features/voting-power/delegations/by-signature` | None | No 3.2 operation. |
| `POST /tokens/{tokenAddress}/participant-role-grants` | `POST /tokens/{assetId}/role-sets` | One call grants and revokes. |
| `POST /tokens/{tokenAddress}/participant-role-revocations` | `POST /tokens/{assetId}/role-sets` | One call grants and revokes. |
| `DELETE /tokens/{tokenAddress}/pause-state` | `PATCH /tokens/{assetId}/pause-state` | Send `paused: false`. |
| `POST /tokens/{tokenAddress}/role-grants` | `POST /tokens/{assetId}/role-sets` | One call grants and revokes. |
| `POST /tokens/{tokenAddress}/role-revocations` | `POST /tokens/{assetId}/role-sets` | One call grants and revokes. |
| `GET /tokens/{tokenAddress}/stats/bond-status` | `GET /tokens/{assetId}/stats` | Set `metric=bondStatus`. |
| `GET /tokens/{tokenAddress}/stats/collateral-ratio` | `GET /tokens/{assetId}/stats` | Set `metric=collateralRatio`. |
| `GET /tokens/{tokenAddress}/stats/supply-changes` | `GET /tokens/{assetId}/stats` | Set `metric=supplyChanges`. |
| `GET /tokens/{tokenAddress}/stats/total-supply` | `GET /tokens/{assetId}/stats` | Set `metric=totalSupply`. |
| `GET /tokens/{tokenAddress}/stats/volume` | `GET /tokens/{assetId}/stats` | Set `metric=volume`. |
| `GET /tokens/{tokenAddress}/stats/wallet-distribution` | `GET /tokens/{assetId}/stats` | Set `metric=walletDistribution`. |
| `GET /tokens/{tokenAddress}/stats/yield-coverage` | `GET /tokens/{assetId}/stats` | Set `metric=yieldCoverage`. |
| `GET /tokens/{tokenAddress}/stats/yield-distribution` | `GET /tokens/{assetId}/stats` | Set `metric=yieldDistribution`. |
| `GET /tokens/{tokenAddress}/transaction-fee-accounting/accrual-events` | `GET /tokens/{assetId}/features/transaction-fee-accounting/accrual-events` |  |
| `GET /tokens/{tokenAddress}/transaction-fee-accounting/exemptions` | `GET /tokens/{assetId}/features/transaction-fee-accounting/exemptions` |  |
| `GET /tokens/{tokenAddress}/transaction-fee-accounting/payers/{payer}` | None | No 3.2 operation. |
| `GET /tokens/{tokenAddress}/transaction-fee-accounting/reconciliations` | `GET /tokens/{assetId}/features/transaction-fee-accounting/reconciliations` |  |
| `GET /tokens/{tokenAddress}/transaction-fee/collections` | `GET /tokens/{assetId}/features/transaction-fee/collections` |  |
| `GET /tokens/{tokenAddress}/transaction-fee/payers/{payer}` | None | No 3.2 operation. |
| `DELETE /transaction-requests/{transactionId}` | None | No 3.2 operation. |
| `POST /transaction-requests/{transactionId}/failures` | `POST /transaction-requests/{transactionId}/transitions` | Send `action: fail` with a reason. |
| `PATCH /transaction-requests/{transactionId}/nonce-tracker` | `POST /transaction-requests/{transactionId}/transitions` | Send `action: nonce` with a reason and nonce. |
| `POST /transaction-requests/{transactionId}/retries` | `POST /transaction-requests/{transactionId}/transitions` | Send `action: retry` with a reason. |
| `GET /user-count-metrics` | None | No v2 operation. The v1 operation `GET /api/v1/user/stats/user-count` serves it. |
| `GET /user-growth-metrics` | None | No v2 operation. The v1 operation `GET /api/v1/user/stats/growth-over-time` serves it. |
| `GET /user-metrics` | None | No v2 operation. The v1 operation `GET /api/v1/user/stats` serves it. |
| `DELETE /users/{userId}/multi-factor-authentication` | `POST /users/{userId}/security/transitions` |  |
| `DELETE /users/{userId}/sessions` | `POST /users/{userId}/security/transitions` |  |
| `POST /users/me/wallets` | `POST /custody/accounts/lifecycle` | Wallets are custody accounts. |
| `GET /wallets/{wallet}/user` | `GET /users` | Filter the list by wallet. A wallet can match more than one user. |
| `POST /webhooks/events/{evtId}/recall` | None | No 3.2 operation. |
| `POST /webhooks/{id}/revoke-previous-secret` | `DELETE /webhooks/{webhookId}/secret-rotations/previous` |  |
| `POST /webhooks/{id}/rotate-secret` | `POST /webhooks/{webhookId}/secret-rotations` |  |

## Next steps [#next-steps]

- [Upgrade a deployment to DALP 3.2](https://docs.settlemint.com/docs/deployment/upgrade-to-3-2) lists the steps for the people who run the platform.
- [Versioning and deprecation](https://docs.settlemint.com/docs/api-reference/guides/versioning-and-deprecation) states how v2 changes from 3.2 onward.
- [Errors](https://docs.settlemint.com/docs/api-reference/guides/errors) describes the error envelope and how to decide on a retry.
