An integration guide for DTCC Digital Assets APIs organized around four core implementation journeys: account management, wallet management, conversion order processing, and corporate action handling. Each section presents the workflow sequence, key endpoints, request and response patterns, business rules, and operational considerations required to implement and operate integrations with the platform.
This reference organizes DTCC Digital Assets APIs by implementation journey rather than by internal service boundary. The guide covers four core journeys: account management, wallet management, conversion order processing, and corporate action handling. Each tab presents a compact workflow summary, a searchable endpoint reference, representative payloads, business rules, status handling, and retry guidance.
| Environment | Identity (Authentication) | Services |
|---|---|---|
| PSE (Pre-Production) | https://api.pse.lds.dtcc-da.com/identity | https://api.pse.lds.dtcc-da.com/services |
| Production | https://api.ledgerscan.dtcc-da.com/identity/ | https://api.ledgerscan.dtcc-da.com/services/ |
/connect/token with grant_type=urn:dtcc:params:oauth:grant-type:service-account-credentials, type=conveyance, entity context, tenant context via acr_values=tenant:{tenantId}, and service-account credentials. Downstream API calls use Authorization: Bearer {access_token}.Each tab starts with a compact flow showing call ordering, parallel-load opportunities, branch behavior, and service dependencies before endpoint-level detail.
Workflows begin with a service account token request using the conveyance model and tenant/entity context. The resulting access token is passed as a bearer token to each API.
Each journey includes business rules, retry guidance, permission considerations, idempotency, async state tracking, and graceful degradation for reference-data failures.
| Journey | Primary APIs | Purpose |
|---|---|---|
| Account Management | /connect/token, /v1/accounts/{accountId}, /v1/accounts/{accountId}/summary, /v1/accounts/{accountId}/activities, /v1/conversion/accounts/{accountId}/balances | Retrieve account detail, hierarchy, access control information, on-chain activity, and security-level balances. |
| Wallet Management | /connect/token, /v1/conversion/wallets, /v1/tracking/networks, /v1/conversion/clients | Load wallet inventory and supporting ledger/account reference data for administration and status tracking. |
| Conversion Orders | /connect/token, /v1/conversion/securities, /v1/conversion/securities/issue-types, /v1/conversion/securities/issue-subtypes, /v1/tracking/networks, /v1/conversion/securities, /v1/conversion/wallets, /v1/conversion/orders, /v1/conversion/async-operations/query, /v1/conversion/orders/{orderId} | Discover eligible securities, retrieve order inputs, submit conversion orders, resolve the order identifier from the async operation, and retrieve order detail. |
| Corporate Actions | /connect/token, /v1/corporate-actions, /v2/corporate-actions/event-types, /v1/conversion/securities, /v2/corporate-actions/{id} | Discover, filter, and inspect corporate action events and lifecycle context. |
This framework defines the Workflow Certification Program for Tokenization Service integrations. The intent of these certifications is not to validate individual API endpoints. Endpoint behavior, request formats, and response structures are already covered by API specifications and implementation guides. Instead, this framework validates that a customer or integration partner can correctly execute the complete business workflows required for production operation.
Complete the ordered sequence of steps that compose each production workflow.
Apply the platform business rules that govern eligibility, direction, and validation.
Handle invalid credentials, expired credentials, access denials, and service failures.
Demonstrate production supportability across the certified workflows.
Sustain and monitor operations after go-live without introducing risk.
Produce request logs, response payloads, and execution output as audit evidence.
Each workflow document follows the same seven-step structure. The objective is to verify that customers can correctly implement the platform's intended workflow patterns rather than simply execute API calls successfully.
Establish a valid session.
Load inputs for the workflow.
Enforce platform constraints.
Perform the operation.
Confirm expected results.
Manage error conditions.
Capture supporting audit artifacts.
The following workflow certifications are currently included within the Tokenization Service certification framework.
All workflow certifications require demonstration of the following.
| Requirement | Detail |
|---|---|
| Authentication | Valid service account authentication. |
| Error Handling | Invalid credentials, expired credentials, access denied, invalid requests, not found conditions, and service failures. |
| Workflow Completion | All required steps executed successfully. |
| Auditability | Request logs, response payloads, execution output, workflow results, and negative-test results. |
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request, invalid parameter, or invalid credentials | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Conversion order submission adds two codes: 409 for a duplicate X-Idempotency-Key, and 422 for a business rule violation such as invalid conversion direction, quantity of zero, or submission outside operational hours.
These workflow certifications serve as the formal production-readiness gate for Tokenization Service integrations.
Participant onboarding establishes the DTCC entity, account hierarchy, wallet structure, administrative access, and service-account readiness required before a participant can begin using Tokenization Services.
A condensed view of the API call sequence, dependencies, and branch rules.
Capture participant name, DTC account information, technical contact, entity administrator, and go-live inputs.
The Integration team uses the Operations Portal to initiate participant onboarding, validate onboarding inputs, and launch the provisioning workflow.
Create the participant entity, DTCC standard account structure, provision wallets, assign controller permissions, create the participant administrator, send onboarding notifications, and activate the participant.
Account Management provides service-account based workflows for retrieving account detail, viewing sub-accounts and linked wallets, interpreting access control metadata, and querying on-chain account activities. Accounts give participants the ability to organize their wallets, and each account is made up of a group of subaccounts or wallets. Two accounts are configured by default: Internal, for wallets a participant uses for its own proprietary purposes, and Clients, for wallets registered on behalf of a participant's clients. Balance, on-chain activity, and the list of wallets mapped to an account are available to view for each account. Account Entity and Activity data are served by the DTCC APIs.
/connect/token with grant_type=urn:dtcc:params:oauth:grant-type:service-account-credentials, type=conveyance, entity context, tenant context via acr_values=tenant:{tenantId}, and service-account credentials. Downstream API calls use Authorization: Bearer {access_token}.A condensed view of the API call sequence, dependencies, and branch rules.
POST /connect/token
Obtain a service-account bearer token.
GET /v1/accounts/{accountId}
Retrieve account and optional access control metadata.
GET /v1/accounts/{accountId}/summary
Retrieve child accounts and linked wallets.
GET /v1/accounts/{accountId}/activities
Retrieve filtered on-chain activity from the DTCC APIs.
Show partial account data if downstream hierarchy or activity services are unavailable.
Retrieves account data and optional page-level access control permissions. This call confirms that the account exists and that the caller has access.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| accountId | path | string | Yes | The account identifier |
| includeObac | query | boolean | Optional | When true, includes access-control information |
const accountResponse = await fetch(
`${baseUrl}/v1/accounts/${accountId}?includeObac=true`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
if (!accountResponse.ok) throw new Error(`Account fetch failed: ${accountResponse.status}`);
const account = await accountResponse.json();{
"accountId": "account-id",
"name": "Example Account",
"externalId": null,
"itemId": null,
"accessControl": { "isController": true, "isShared": false, "hasShareRequest": false }
}interface AccountWithAccessControlResponse {
accountId: string;
name: string;
externalId: string | null;
itemId: string | null;
accessControl: AccessControlInfo | null;
}
interface AccessControlInfo {
isController: boolean;
isShared: boolean;
hasShareRequest: boolean;
}Handle 401 by requesting a new JWT access credential and retrying once; handle 403 as account lockout or access denied; handle 404 as account not found; validate bad requests client-side before submission.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Read-only GET; safe to retry on 5xx or network timeout. Do not retry credential requests on 4xx.
Returns child accounts and linked wallets below a parent account for display and access-control interpretation.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| accountId | path | string UUID | Yes | The parent account identifier |
| includeObac | query | boolean | Yes | Always true to include access control metadata per item |
| limit | query | integer | Optional | Pagination page size |
| offset | query | integer | Optional | Pagination offset |
| type | query | string | Optional | Filter: Account or Wallet |
| search | query | string | Optional | Search by name |
GET /v1/accounts/{accountId}/summary
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | entityType | AccountHierarchyEntityType | Wallet, Account |
| Output (response) | trackingStatus | TrackingStatus | None, Enabled, Disabled, Enabling, Disabling |
| Output (response) | linkageStatus | LinkageStatus | Linking, Unlinking, Linked |
const summaryResponse = await fetch(
`${baseUrl}/v1/accounts/${accountId}/summary?includeObac=true`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
const summaryItems = await summaryResponse.json();
const accountIds = summaryItems.filter(i => i.type === 'Account').map(i => i.id);
const walletIds = summaryItems.filter(i => i.type === 'Wallet').map(i => i.id);[
{ "id": "account-1", "name": "Sub Account", "type": "Account", "lockedOperations": ["Updating"] },
{ "id": "wallet-1", "name": "Wallet A", "type": "Wallet", "walletDetails": { "address": "0x..." } }
]interface AccountSummary {
id: string;
name: string;
type: 'Account' | 'Wallet';
externalId?: string;
lockedOperations?: string[];
walletDetails?: { address: string };
accessControl?: { isShared: boolean };
}If the summary fetch fails, account data may still be shown while hierarchy detail is unavailable; present a partial state and a retry option.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Read-only GET; safe to retry on 5xx or network timeout.
Retrieves paginated on-chain activities with date range, activity type, network, source wallet, destination wallet, pagination, and sorting filters.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| accountId | path | string UUID | Yes | Parent or sub-account identifier |
| startDate | query | ISO 8601 string | Optional | Filter activities from this date; defaults to the current week if omitted |
| endDate | query | ISO 8601 string | Optional | Filter activities until this date; clamp future values to now |
| activityType | query | string | Optional | Filter by activity type |
| network | query | string | Optional | Ledger network filter |
| fromWalletId | query | string UUID | Optional | Source wallet filter |
| toWalletId | query | string UUID | Optional | Destination wallet filter |
| limit / offset | query | integer | Optional | Pagination controls |
| sortBy / sortOrder | query | string | Optional | Sorting controls |
GET /v1/accounts/{accountId}/activities
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
const params = new URLSearchParams();
params.set('startDate', startDate.toISOString());
params.set('endDate', endDate.toISOString());
if (activityType) params.set('activityType', activityType);
if (network) params.set('network', network);
if (fromWalletId) params.set('fromWalletId', fromWalletId);
if (toWalletId) params.set('toWalletId', toWalletId);
const activitiesResponse = await fetch(
`${baseUrl}/v1/accounts/${accountId}/activities?${params.toString()}`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
const activities = await activitiesResponse.json();{
"items": [{
"ledger": "Ethereum",
"wallet": { "id": "wallet-1", "name": "Source Wallet", "walletId": "0x..." },
"primaryCounterWallet": { "id": "wallet-2", "name": "Destination Wallet", "walletId": "0x..." },
"createdAt": "2026-01-01T00:00:00Z",
"totalValue": 500,
"pricedInItem": "TOKEN",
"status": "Completed",
"operations": [{ "amount": 500, "token": { "symbol": "TOK" } }]
}],
"metadata": { "asOfDate": "2026-01-01T00:00:00Z" }
}interface AccountActivitiesWithMetaDataApiModel {
items: AccountActivitiesApiModel[];
metadata: { asOfDate: string };
}fee, payment, paymentreceived, mint, burn, debit, credit, freeze, unfreeze, partialfreeze, partialunfreeze, revoked, and clawedback.
The response includes metadata with asOfDate, indicating the point-in-time represented by the activity data.
Handle invalid filters as 400; expired credentials as 401; access restrictions as 403; service failures as error states with retry. Activity retrieval fails independently of account retrieval, so account detail remains displayable when activity retrieval fails.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Continue to display account detail without activities. |
Read-only GET; safe to retry on 5xx or network timeout. If the activity service is unavailable, show account details without activities rather than failing the whole view.
Retrieves balance records for an account.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| accountId | path | string | Yes | Identifier of the account whose balances are being queried; the same identifier used by /v1/accounts/{accountId}, and it must be accessible under the calling service account's permissions. |
GET /v1/conversion/accounts/{accountId}/balances
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | status | FinancialSecurityStatus | Onboarding, Active, Pause, Failed |
| Output (response) | type | WalletTypes | Internal, Client |
const balancesResponse = await fetch(
`${baseUrl}/v1/conversion/accounts/${accountId}/balances`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
if (!balancesResponse.ok) throw new Error(`Balance retrieval failed: ${balancesResponse.status}`);
const balances = await balancesResponse.json();{
"items": [
{
"cusip": "037833100",
"security": "Apple Inc. Common Stock",
"issueSubType": {
"id": "1",
"code": "CS",
"description": "Common Stock"
},
"totalQuantity": 131,
"walletsCount": 2,
"ledgersCount": 2,
"holders": [
{
"quantity": 101,
"wallet": {
"id": "06572a05-8033-4088-8b0a-01faa6ed74df",
"name": "First Bank EVM Wallet",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
},
"ledger": {
"name": "Ethereum",
"network": "Ethereum_Mainnet"
}
},
{
"quantity": 30,
"wallet": {
"id": "1b6e961b-6c6a-4726-8f4c-f2330a5782fa",
"name": "American Bank Besu Wallet",
"walletAddress": "0x4bDb16A35fc5fdc4A8701Bc5B688D254E99027c0"
},
"ledger": {
"name": "Besu private",
"network": "Besu"
}
}
]
}
],
"metadata": {
"asOfDate": "2026-05-18T00:00:00Z"
}
}interface AccountBalancesResponse {
items: AccountSecurityBalancesResponse[];
metadata: AccountBalancesMetadataResponse;
}
interface AccountSecurityBalancesResponse {
cusip: string;
security: string;
issueSubType: { id: string; code: string; description: string };
totalQuantity: number;
walletsCount: number;
ledgersCount: number;
holders: SecurityBalanceHolder[];
}
interface SecurityBalanceHolder {
quantity: number;
wallet: { id: string; name: string; walletAddress: string };
ledger: { name: string; network: string };
}
interface AccountBalancesMetadataResponse {
asOfDate: string;
}The response includes metadata with asOfDate, indicating the point-in-time represented by the balance data.
Handle 401 by requesting a new JWT access credential and retrying once; handle 403 as either an insufficient permission scope or an account the service account is not authorized for; handle 404 as an unknown or inaccessible account identifier and correct the value rather than retrying.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Read-only GET; safe to retry on 5xx or network timeout using exponential backoff with a bounded retry limit. Because this call is expected to run frequently as part of pre-conversion checks and scheduled reconciliation, refresh the JWT access credential proactively ahead of its expiry rather than re-authenticating reactively after a 401.
This endpoint uses the OAuth 2.0 Client Credentials grant with client_id, client_secret, and scope. It does not use the Service Account Credentials grant documented elsewhere in this guide. Request the credential from /connect/token with grant_type=client_credentials before calling this endpoint.
Demonstrate that a customer integration can authenticate using a service account, retrieve an account, retrieve account hierarchy information, retrieve account activities, retrieve and reconcile account balances, and correctly handle expected errors and service failures. The purpose of this test is to certify that the integration correctly implements the Account Management workflow before production access is granted.
Five sequential stages. Stages two through four depend on the JWT access credential issued in stage one. Stage five obtains its own credential using a different grant.
Obtain a JWT access credential using SA-AccountBot.
Confirm the account identifier matches the request.
Retrieve child accounts and linked wallets.
Retrieve paginated activities with asOfDate.
Retrieve, reconcile, and interpret security-level balances.
Provisioned service account, service account password, tenant ID, and a valid account ID. Service accounts and permissions are provisioned by DTCC. Step five additionally requires a registered client ID, client secret, and an authorized scope granting access to the balances endpoint.
const tenantId = "<tenant-id>";
const accountId = "<account-id>";
const baseUrl = "<base-url>";
const username = "SA-AccountBot";
const password = process.env.SERVICE_ACCOUNT_PASSWORD!;
// Step 5 only: OAuth 2.0 Client Credentials grant
const clientId = process.env.CLIENT_ID!;
const clientSecret = process.env.CLIENT_SECRET!;
const scope = process.env.API_SCOPE!;This step validates that the integration can obtain a JWT access credential from the Identity Server using service account credentials. The JWT access credential proves the caller's identity and must be supplied as a bearer credential on every subsequent API call in this workflow.
async function authenticate() {
const response = await fetch(`${baseUrl}/connect/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "urn:dtcc:params:oauth:grant-type:service-account-credentials",
type: "conveyance",
entity: username,
acr_values: `tenant:${tenantId}`,
username,
password
})
});
if (!response.ok) {
throw new Error(`Authentication failed: ${response.status}`);
}
const data = await response.json();
return data.access_token;
}HTTP 200; JWT access credential returned; credential accepted by downstream APIs.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid credentials; invalid_client | Surface authentication rejected. Do not retry with the same credentials. |
| 500, 503 | Identity Server failure | Retry with exponential backoff, maximum three attempts. |
Verify the integration can retrieve account information.
async function getAccount(accessToken: string, accountId: string) {
const response = await fetch(
`${baseUrl}/v1/accounts/${accountId}?includeObac=true`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
if (!response.ok) {
throw new Error(`Account retrieval failed: ${response.status}`);
}
return response.json();
}{
accountId: string,
name: string
}HTTP 200; account returned; account identifier matches request; response successfully parsed. The workflow requires account resolution before subsequent operations.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 403 | Insufficient permissions | Surface access denied. Do not retry. |
| 404 | Account not found | Surface account not found. Do not retry. |
Verify the integration can retrieve child accounts and linked wallets.
async function getHierarchy(accessToken: string, accountId: string) {
const response = await fetch(
`${baseUrl}/v1/accounts/${accountId}/summary?includeObac=true`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
if (!response.ok) {
throw new Error(`Summary retrieval failed: ${response.status}`);
}
return response.json();
}[
{
id: string,
name: string,
type: "Account" | "Wallet"
}
]The summary endpoint returns a combined hierarchy view of child accounts and linked wallets.
HTTP 200; hierarchy returned; child entities visible; wallets visible; no parsing errors.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 403 | Insufficient permissions | Surface access denied. Do not retry. |
| 500, 503 | Service failure | Display account detail without hierarchy and offer retry. |
Verify the integration can retrieve activities.
async function getActivities(accessToken: string, accountId: string) {
const response = await fetch(
`${baseUrl}/v1/accounts/${accountId}/activities`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
if (!response.ok) {
throw new Error(`Activity retrieval failed: ${response.status}`);
}
return response.json();
}{
items: [],
metadata: {
asOfDate: string
}
}The activities workflow retrieves paginated activity data and includes metadata such as asOfDate.
HTTP 200; activities returned; metadata returned; data successfully parsed.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid filter or query parameter | Correct the filter values. Do not retry as-is. |
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 500, 503 | Activity service failure | Account data remains available; fail activity retrieval gracefully with a clear error message. |
Verify the integration can retrieve security-level account balances, interpret the balance payload, reconcile aggregate totals against holder allocations, and process the response metadata.
This endpoint uses the OAuth 2.0 Client Credentials grant rather than the Service Account Credentials grant used in Step 1, so it obtains its own credential before calling.
typescriptasync function authenticateForBalances() {
const response = await fetch(`${baseUrl}/connect/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: clientId,
client_secret: clientSecret,
scope
})
});
if (!response.ok) throw new Error(`Authentication failed: ${response.status}`);
return response.json();
}
async function getBalances(accessToken: string, accountId: string) {
const response = await fetch(
`${baseUrl}/v1/conversion/accounts/${accountId}/balances`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
if (!response.ok) throw new Error(`Balance request failed: ${response.status}`);
return response.json();
}
const tokenResponse = await authenticateForBalances();
const balances = await getBalances(tokenResponse.access_token, accountId);Confirm the credential response returns an access token, a token type of Bearer, and an expiration value. Confirm the balance response returns an items collection and a metadata object.
{
cusip: string,
security: string,
issueSubType: { id: string, code: string, description: string },
totalQuantity: number,
walletsCount: number,
ledgersCount: number,
holders: []
}Every balance record must carry a CUSIP, security name, issue sub-type, total quantity, wallet count, ledger count, and holder records. Total quantity, wallet count, and ledger count must each be zero or greater, and holder records must be present wherever balances exist.
typescriptfor (const item of balances.items) {
const holderTotal = item.holders.reduce(
(sum, holder) => sum + holder.quantity,
0
);
if (holderTotal !== item.totalQuantity) {
throw new Error("Balance reconciliation failed");
}
}Aggregate balances must reconcile with holder-level allocations, so the sum of holder quantities equals totalQuantity. Using the sample response, holders of 101 and 30 reconcile to a total of 131.
HTTP 200; balance data retrieved; payload interpreted; aggregate totals reconcile with holder allocations; balance snapshot date available.
This endpoint returns three distinct error envelope shapes depending on which layer rejects the request.
| HTTP | Condition | Response body | Expected integration behavior |
|---|---|---|---|
| 400 | Malformed authentication request | errorCode, message, requestId, tracingUrl | Correct the request encoding and verify all required fields are present. Do not retry as-is. |
| 401 | Invalid client credentials | errorCode, message, requestId, tracingUrl | Authentication rejected. Verify credentials before retrying. |
| 401 | Expired or missing access token; GATEWAY__UNAUTHENTICATED | ErrorCode, ErrorMessage | Re-authenticate, then retry once. |
| 403 | Requested scope not permitted for this client | errorCode, message, requestId, tracingUrl | Confirm the scope string matches what was granted at registration. Do not retry. |
| 403 | Token does not grant access to this account; GATEWAY__ACCESSDENIED | ErrorCode, ErrorMessage | Surface access denied. Do not retry. |
| 403 | User locked out; AUTHORIZATION_ENGINE__USER_LOCKED_OUT_EXCEPTION | ErrorCode, ErrorMessage | Surface the lockout. Do not retry until the lockout is cleared. |
| 404 | Account identifier does not exist or is not accessible | errorCode, message, requestId, tracingUrl | Validate the account identifier before calling. Do not retry without correcting it. |
| 500, 503 | Service failure | errorCode, errorMessage | Retry with exponential backoff and a bounded retry count. Surface the failure once retries are exhausted and terminate the workflow safely. |
Access tokens are time-limited. Cache the credential, refresh it proactively ahead of expiry rather than reacting to a 401, and never reuse an expired token.
Execute the complete workflow in a single transaction.
async function runWorkflow() {
const token = await authenticate();
const account = await getAccount(token, accountId);
const hierarchy = await getHierarchy(token, accountId);
const activities = await getActivities(token, accountId);
const balanceToken = await authenticateForBalances();
const balances = await getBalances(balanceToken.access_token, accountId);
return { account, hierarchy, activities, balances };
}Authenticate PASS
Retrieve Account PASS
Retrieve Hierarchy PASS
Query Activity PASS
Query Balances PASS
Workflow Complete PASSEach constituent call returns its expected success code.
| ID | Scenario | HTTP | Expected result |
|---|---|---|---|
| NT-1 | Invalid Credentials | 400 | Authentication rejected with invalid_client. Invalid client credentials are an expected authentication failure scenario. |
| NT-2 | Expired Credential | 401 | Re-authentication required. |
| NT-3 | Invalid Account | 404 | Account Not Found. |
| NT-4 | Access Denied | 403 | Access Denied for insufficient permissions. |
| NT-5 | Activity Service Failure | 500, 503 | Account data remains available, activity retrieval fails gracefully, and the user receives a clear error message. |
| NT-6 | Invalid Client Credentials (Step 5) | 401 | Authentication rejected. Verify credentials before retrying. |
| NT-7 | Invalid Scope (Step 5) | 403 | Access denied. Confirm the scope string matches what was granted at registration. |
| NT-8 | Expired Balance Token (Step 5) | 401 | Re-authentication required; GATEWAY__UNAUTHENTICATED. |
| NT-9 | Unauthorized Account Access (Step 5) | 403 | Access denied; GATEWAY__ACCESSDENIED. |
| NT-10 | Locked Out User (Step 5) | 403 | Lockout detected; AUTHORIZATION_ENGINE__USER_LOCKED_OUT_EXCEPTION. |
| NT-11 | Malformed Authentication Request (Step 5) | 400 | Bad request. Correct the request encoding and confirm all required fields are present. |
| NT-12 | Balance Service Failure (Step 5) | 500, 503 | Retry logic executed, failure reported, and the workflow terminated safely. |
A customer is certified only on successful authentication, account retrieval, hierarchy retrieval, activity retrieval, and balance retrieval with payload validation, reconciliation, and metadata processing, plus token lifecycle management and a bounded retry strategy, plus proper error handling for invalid credentials, expired credentials, invalid account, invalid scope, access denied, user lockout, malformed authentication requests, and service failures, plus evidence collection showing each stage completed successfully.
Wallet Management covers wallet inventory and ledger/account reference data used to support wallet administration and status tracking. This guide version focuses on wallet discovery and reference-data retrieval APIs.
/connect/token with grant_type=urn:dtcc:params:oauth:grant-type:service-account-credentials, type=conveyance, entity context, tenant context via acr_values=tenant:{tenantId}, and service-account credentials. Downstream API calls use Authorization: Bearer {access_token}.A condensed view of the API call sequence, dependencies, and branch rules.
POST /connect/token
Obtain service-account token.
GET /v1/conversion/wallets
Display current wallet inventory.
GET /v1/tracking/networksGET /v1/conversion/clients
Load in parallel.
Use wallet inventory views to monitor wallet state and status changes.
Loads existing wallets for inventory display and status review.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| Count | query | integer | Optional | Page size |
| Offset | query | integer | Optional | Pagination offset |
| search | query | string | Optional | Search by wallet name |
| networks | query | string[] | Optional | Filter by network name |
| type | query | string | Optional | internal or client |
| sortBy / sortOrder | query | string | Optional | Sorting controls |
GET /v1/conversion/wallets
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | WalletFields | Name, Network, CreatedAt |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | type | WalletTypes | Internal, Client |
| Output (response) | state | ProcessingStates | Idle, Registering, FailedCompliance, Failed |
const walletsResponse = await fetch(`${baseUrl}/v1/conversion/wallets`, {
headers: { 'Authorization': `Bearer ${access_token}` }
});
const wallets = await walletsResponse.json();[
{ "id": "wallet-1", "name": "Example Wallet", "type": "CLIENT", "network": "Ethereum", "walletAddress": "0x...", "state": "Idle" }
]interface WalletSummary {
id: string;
name: string;
type: string;
network: string;
walletAddress: string;
account: AccountDetails;
state: string;
participant?: Participant;
}Handle 401 by requesting a new JWT access credential and retrying once; handle 5xx with retry and a visible error state. Wallet registration is not available through this API, so no create or update failure paths apply.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Terminate the inventory view safely if the failure persists. |
Read-only GET; safe to retry on 5xx or network timeout.
Fetches available ledger networks from the DTCC APIs and existing accounts from the DTCC APIs in parallel.
GET /v1/tracking/networks
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | networkStatus | NetworkStatus | Active, Inactive, NA |
GET /v1/conversion/clients
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
const [networksResponse, accountsResponse] = await Promise.all([
fetch(`${baseUrl}/v1/tracking/networks`, { headers: { 'Authorization': `Bearer ${access_token}` } }),
fetch(`${baseUrl}/v1/conversion/clients`, { headers: { 'Authorization': `Bearer ${access_token}` } })
]);
const networks = await networksResponse.json();
const accounts = await accountsResponse.json();
const availableNetworks = networks.filter(n =>
n.networkStatus === 'Active' &&
n.name !== 'Classic' &&
n.name !== 'Ethereum_Mainnet'
);[
{
"name": "Ethereum_Mainnet",
"displayName": "Ethereum Mainnet",
"networkStatus": "Active",
"nodeFormats": ["EVM"],
"listenerEnabled": true
},
{
"name": "Canton",
"displayName": "Canton",
"networkStatus": "Active",
"nodeFormats": ["Canton"],
"listenerEnabled": true
}
]json · /v1/conversion/clients[
{ "name": "Example Account", "externalId": "external-id", "id": "account-id" }
]interface NetworkApiModel {
name: string;
displayName: string;
networkStatus: string;
nodeFormats: string[];
listenerEnabled: boolean;
}
interface AccountDetails { name: string; externalId: string; id?: string; entityId?: string; }If ledger or client reference data fails, wallet context may be incomplete; present a retry path and keep the wallet inventory visible. Both reference-data calls fail independently of the wallet inventory call.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Keep wallet inventory available and present a meaningful error rather than terminating the workflow. |
Reference data GETs are read-only and safe to retry. Both calls run in parallel and must resolve before inventory review begins.
Demonstrate that a customer integration can authenticate with a service account, load wallet inventory, load ledger reference data, load account and client reference data, review wallet inventory, and track wallet status. This certification verifies that the customer can correctly consume wallet-related APIs and construct an operational view of wallet inventory and status. The workflow is read-only and intended to support wallet administration and operational monitoring.
Authenticate once, load wallet inventory, then retrieve ledger and client reference data in parallel before reviewing inventory and tracking status.
Obtain a JWT access credential using SA-WalletReader.
GET /v1/conversion/wallets
/v1/tracking/networks + /v1/conversion/clients in parallel.
Correlate wallets with client and account data.
Extract and review wallet status values.
Tenant ID, service account, service account password, base URL, and known wallet data. Required access: /connect/token, /v1/conversion/wallets, /v1/tracking/networks, /v1/conversion/clients.
const tenantId = "<tenant-id>";
const baseUrl = "<base-url>";
const username = "SA-WalletReader";
const password = process.env.SERVICE_ACCOUNT_PASSWORD!;async function authenticate() {
const response = await fetch(`${baseUrl}/connect/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "urn:dtcc:params:oauth:grant-type:service-account-credentials",
type: "conveyance",
entity: username,
acr_values: `tenant:${tenantId}`,
username,
password
})
});
if (!response.ok) throw new Error(`Authentication failed: ${response.status}`);
const data = await response.json();
return data.access_token;
}
async function getWallets(accessToken: string) {
const response = await fetch(`${baseUrl}/v1/conversion/wallets`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) throw new Error(`Wallet retrieval failed: ${response.status}`);
return response.json();
}
async function getLedgers(accessToken: string) {
const response = await fetch(`${baseUrl}/v1/tracking/networks`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) throw new Error(`Ledger retrieval failed: ${response.status}`);
return response.json();
}
async function getClients(accessToken: string) {
const response = await fetch(`${baseUrl}/v1/conversion/clients`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) throw new Error(`Client retrieval failed: ${response.status}`);
return response.json();
}This step validates that the integration can obtain a JWT access credential from the Identity Server using service account credentials. The JWT access credential proves the caller's identity and must be supplied as a bearer credential on every subsequent API call in this workflow.
const accessToken = await authenticate();HTTP 200; JWT access credential returned; credential accepted by downstream APIs. Evidence: authentication successful, credential received.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid credentials; invalid client | Surface authentication rejected. Do not retry with the same credentials. |
| 500, 503 | Identity Server failure | Retry with exponential backoff, maximum three attempts. |
Verify wallet inventory can be retrieved.
const wallets = await getWallets(accessToken);Wallet data returned; response is non-empty; wallet identifiers present.
HTTP 200; wallet inventory successfully loaded. Evidence: wallet inventory response, wallet count.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid query parameters such as an invalid sort field or malformed filter | Correct the request. Do not retry as-is. |
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 403 | Missing permission | Surface access denied. Do not retry. |
| 500, 503 | Wallet endpoint failure | Inventory unavailable; surface the failure and terminate the workflow safely. |
Verify ledger and client reference data can be loaded in parallel.
const [ledgers, clients] = await Promise.all([
getLedgers(accessToken),
getClients(accessToken)
]);Available ledgers returned; available client records returned.
HTTP 200 on both calls; reference data available and usable; parallel execution succeeds. Evidence: ledger response, client response.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 403 | Missing permission | Surface access denied. Do not retry. |
| 500, 503 | Reference data failure | Detect the failure, present a meaningful error, and keep the workflow running with wallet inventory still available. |
Verify wallet inventory can be correlated with reference data.
const inventoryView = wallets.map(wallet => ({
wallet,
client: clients.find(c => c.id === wallet.clientId)
}));Wallets visible; wallets associated with client and account data; inventory records complete.
Inventory review completed. Evidence: sample wallet records, reference-data mapping.
This step performs no additional API calls. If reference data was unavailable in Step 3, the integration must present the inventory without client correlation rather than failing the review.
Verify wallet status data is visible and reviewable.
const walletStatuses = wallets.map(wallet => ({
walletId: wallet.id,
status: wallet.status
}));Status field available; status values populated; statuses can be reported.
Wallet state visible; wallet status review completed. Evidence: status report, sample wallet statuses.
This step performs no additional API calls. If the status field is absent from the wallet inventory response, treat the step as failed rather than defaulting to an assumed status.
Execute the complete wallet management workflow in a single run to confirm every stage succeeds in sequence.
async function executeWalletWorkflow() {
const token = await authenticate();
const wallets = await getWallets(token);
const [ledgers, clients] = await Promise.all([
getLedgers(token),
getClients(token)
]);
return { wallets, ledgers, clients };
}Authenticate PASS
Load Wallets PASS
Load Ledgers PASS
Load Clients PASS
Review Inventory PASS
Track Status PASS
Workflow Complete PASSEach constituent call returns its expected success code.
| ID | Scenario | HTTP | Expected result |
|---|---|---|---|
| NT-1 | Invalid Credentials | 400 | Authentication rejected; invalid client. |
| NT-2 | Expired Credential | 401 | Re-authentication required. |
| NT-3 | Missing Permission | 403 | Access denied. |
| NT-4 | Invalid Query Parameters | 400 | Validation error, for example an invalid sort field or malformed filter. |
| NT-5 | Reference Data Failure | 500, 503 | Failure detected; meaningful error presented; workflow does not crash. |
| NT-6 | Wallet Endpoint Failure | 500, 503 | Inventory unavailable; failure surfaced; workflow terminated safely. |
A customer is certified only on successful authentication, wallet inventory retrieval, ledger retrieval, client retrieval, inventory review, and wallet-status review, plus proper handling of all negative tests.
Conversion Operations covers discovery of registered securities, filter reference data, active securities for order entry, eligible idle wallets, and conversion order submission. Conversions are the mechanism for clients to convert securities between electronic book entry and digital tokenized forms. When submitting a conversion order, the participant selects the source wallet and the destination wallet. The process for converting securities from electronic to digital and back to electronic is identical; the only difference is what is assigned as the source and destination of the securities. Submission is asynchronous and returns no response body, so the integration polls the async operation with its idempotency key to obtain the order identifier before retrieving the order. Submitted orders are processed straight through, moving from Processing to Completed.
/connect/token as application/x-www-form-urlencoded with grant_type=client_credentials, client_id, client_secret, and the required scope. Downstream API calls use Authorization: Bearer {access_token}. This departs from the Service Account Credentials grant used by the other API families.A condensed view of the API call sequence, dependencies, and branch rules.
POST /connect/token
Obtain service-account token.
GET /v1/conversion/securitiesGET /v1/conversion/securities/issue-typesGET /v1/conversion/securities/issue-subtypesGET /v1/tracking/networks in parallel.
GET /v1/conversion/securities?status=ActiveGET /v1/conversion/wallets in parallel.
Use Active securities and wallets that are Idle and conversion eligible.
POST /v1/conversion/orders
Returns 202 Accepted with no body. Retain the idempotency key.
POST /v1/conversion/async-operations/query
Poll with the idempotency key until resourceId is populated.
GET /v1/conversion/orders/{orderId}
Use resourceId as the order identifier.
Orders are processed straight through from Processing to Completed. Failed is terminal.
resourceId.Fetches a paginated securities list alongside issue type, issue sub-type, and ledger network reference data.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| Offset / Count | query | integer | Optional | Controls which slice of the securities list is returned, where offset sets the starting position and limit sets the number of records per page. |
| search | query | string | Optional | Free-text term matched against issuer name, security name, or CUSIP to narrow the securities list. |
| network | query | string | Optional | Restricts results to securities tokenized on a single ledger network, using a network name returned by the ledgers endpoint. |
| issueTypeId | query | string | Optional | Restricts results to a high-level security classification such as equity or debt, referenced by an identifier from the issue types endpoint. |
| issueSubTypeId | query | string | Optional | Restricts results to a finer classification nested beneath the high-level type, such as common stock, referenced by an identifier from the issue sub-types endpoint. |
| sortBy / sortOrder | query | string | Optional | Determines which field the securities list is ordered on and whether that order runs ascending or descending. |
GET /v1/conversion/securities
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | FinancialSecurityFields | CUSIP, Description, Issuer |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | status | FinancialSecurityStatus | Onboarding, Active, Pause, Failed |
| Output (response) | processingState | ProcessingStates | Idle, Registering, FailedCompliance, Failed |
GET /v1/conversion/securities/issue-types
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
GET /v1/conversion/securities/issue-subtypes
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
GET /v1/tracking/networks
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | networkStatus | NetworkStatus | Active, Inactive, NA |
const [securitiesResponse, issueTypesResponse, issueSubTypesResponse, ledgersResponse] = await Promise.all([
fetch(`${baseUrl}/v1/conversion/securities?offset=0&limit=25`, { headers: { 'Authorization': `Bearer ${access_token}` } }),
fetch(`${baseUrl}/v1/conversion/securities/issue-types`, { headers: { 'Authorization': `Bearer ${access_token}` } }),
fetch(`${baseUrl}/v1/conversion/securities/issue-subtypes`, { headers: { 'Authorization': `Bearer ${access_token}` } }),
fetch(`${baseUrl}/v1/tracking/networks`, { headers: { 'Authorization': `Bearer ${access_token}` } })
]);
const securities = await securitiesResponse.json();[
{ "id": "security-id", "cusip": "123456789", "issuerName": "Example Issuer", "security": "Example Security", "securitySymbol": "EX", "status": "Active", "tokens": [{ "ledgerId": "ledger-id", "name": "Token", "ledger": { "name": "Ethereum", "network": "Ethereum" } }] }
]interface EligibleSecurityApiModel {
id: string;
cusip: string;
issuerName: string;
security: string;
securitySymbol: string;
issueType: IssueType;
issueSubType: IssueType;
tokens: EligibleSecurityToken[];
status: string;
trackingTrancheId: string;
}
interface IssueType { id: string; code: string; description: string; }The securities response includes embedded token and ledger network associations, reducing the need for per-security lookup calls. Issue type, issue sub-type, and network are independent filter dimensions.
If securities fail to load, show an error state. If issue type, issue sub-type, or ledger reference data fails, disable the corresponding filter while still rendering the securities list.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Disable only the affected filter rather than the whole view. |
All four endpoints are read-only GETs and safe to retry on 5xx or network timeout.
Loads order-entry inputs in parallel and filters wallets to Idle state.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| status | query | string | Yes | Active |
| Offset / Count | query | integer | Optional | Pagination controls |
| participantId | query | string | Optional | The 8-digit DTC participant number that identifies the member firm whose wallets are being retrieved, for example 00002667. This is the same identifier used across all DTC and DTCC services to uniquely identify a participant. |
GET /v1/conversion/securities
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | FinancialSecurityFields | CUSIP, Description, Issuer |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | status | FinancialSecurityStatus | Onboarding, Active, Pause, Failed |
| Output (response) | processingState | ProcessingStates | Idle, Registering, FailedCompliance, Failed |
GET /v1/conversion/wallets
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | WalletFields | Name, Network, CreatedAt |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | type | WalletTypes | Internal, Client |
| Output (response) | state | ProcessingStates | Idle, Registering, FailedCompliance, Failed |
const [securitiesResponse, walletsResponse] = await Promise.all([
fetch(`${baseUrl}/v1/conversion/securities?status=Active`, { headers: { 'Authorization': `Bearer ${access_token}` } }),
fetch(`${baseUrl}/v1/conversion/wallets`, { headers: { 'Authorization': `Bearer ${access_token}` } })
]);
const securities = await securitiesResponse.json();
const wallets = await walletsResponse.json();
const eligibleWallets = wallets.filter(w => w.state === 'Idle');{
"securities": [
{ "id": "security-id", "cusip": "123456789", "issuerName": "Example Issuer", "security": "Example Security", "status": "Active" }
],
"wallets": [
{ "id": "wallet-id", "name": "Example Wallet", "type": "INTERNAL", "network": "DTC_Classic", "walletAddress": "0x...", "state": "Idle" }
]
}interface Security {
id: string;
cusip: string;
issuerName: string;
security: string;
securitySymbol?: string;
issueType: IssueType;
issueSubType: IssueType;
status: string;
trackingTrancheId: string;
}
interface WalletSummary {
id: string;
name: string;
type: string;
network: string;
walletAddress: string;
account: AccountDetails;
state: string;
participant?: Participant;
}Only Active securities are eligible for orders. A wallet is eligible as a source or destination candidate only when its processing state is Idle and conversionEligible is true. Both conditions must hold; an Idle wallet that is not conversion eligible must be excluded.
Handle 401 by requesting a new JWT access credential and retrying once; handle 5xx with retry and an error state. If no Active security or no Idle wallet is returned, block order submission rather than submitting an ineligible order.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid query parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Block order submission until inputs load successfully. |
Both calls are read-only GETs and safe to retry on 5xx or network timeout.
Prior to submitting a conversion order, we recommend to retrieve and check the wallet and securities from the appropriate endpoints.
Submission is asynchronous. POST /v1/conversion/orders returns 202 Accepted with no response body, so the order identifier is not available on the submission response. Retain the X-Idempotency-Key supplied at submission, poll POST /v1/conversion/async-operations/query with that key until resourceId is populated, then retrieve the order from GET /v1/conversion/orders/{orderId}. Orders are processed straight through, entering Processing and settling at Completed.
GET /v1/conversion/orders
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| searchFor | query | string | Optional | Free-text search key filter |
| fromWallet | query | string | Optional | Source wallet identifier filter |
| toWallet | query | string | Optional | Destination wallet identifier filter |
| updateFrom / updateTo | query | string | Optional | Lower and upper bounds of the update date range |
| ids | query | array | Optional | Filter by specific order identifiers |
| financialSecurityIds | query | array | Optional | Filter by security identifiers |
| status | query | array | Optional | Filter by order status |
| origin | query | array | Optional | Filter by how the order was originated |
| includeObac | query | boolean | Optional | Include access control metadata when true |
| orderBy / sortOrder | query | string | Optional | Sorting controls |
| Offset / Count | query | integer | Optional | Pagination controls |
POST /v1/conversion/orders
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| X-Idempotency-Key | header | string | Yes | Max 255 characters; prevents duplicate submissions. Retain this value for the async operation query. |
| financialSecurityId | body | string UUID | Yes | Security being converted |
| fromWalletId | body | string UUID | Yes | The source account or wallet from which the position will be debited. For Classic accounts, the format is {participantId}-10 (Free NA) or {participantId}-11 (Free MA), for example 00002667-10. These are auto-generated at onboarding and retrievable via GET /v1/conversion/wallets. For digital wallets, this is the registered blockchain wallet address. |
| toWalletId | body | string UUID | Yes | The destination account or wallet to which the converted position will be credited. For Classic accounts, the format is {participantId}-10 (Free NA) or {participantId}-11 (Free MA), for example 00002667-10. These are auto-generated at onboarding and retrievable via GET /v1/conversion/wallets. For digital wallets, this is the registered blockchain wallet address. |
| activityType | body | string | Yes | MemoSeg reduction reason code indicating how the conversion affects the participant's segregated position. Code 040 reduces (debits) the MemoSeg quantity; code 098 leaves the MemoSeg position unchanged. |
| quantity | body | string | Yes | Amount to convert; must be greater than zero |
| participantId | body | string | Optional | The 8-digit DTC participant number that identifies the member firm on whose behalf the conversion order is submitted, for example 00002667. This is the same identifier used across all DTC and DTCC services to uniquely identify a participant. |
| note | body | string | Optional | Optional order note |
POST /v1/conversion/async-operations/query
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| idempotencyKeys | body | array | Yes | One or more idempotency keys retained from prior submissions |
| Offset / Count | body | integer | Optional | Pagination controls |
GET /v1/conversion/orders/{orderId}
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| orderId | path | string UUID | Yes | Order identifier, taken from resourceId on the async operation response |
GET /v1/conversion/orders
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | OrderFields | CreatedAt, UpdatedAt |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Input (query) | status | OrderStatus | Processing, Completed, Failed |
| Input (query) | origin | OrderOrigin | Participant, Admin, ForcedReconversion |
| Output (response) | status | OrderStatus | Processing, Completed, Failed |
| Output (response) | origin | OrderOrigin | Participant, Admin, ForcedReconversion |
POST /v1/conversion/async-operations/query
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | objectKind | ObjectKind | Undefined, Order, Wallet, FinancialSecurity |
| Output (response) | status | AsyncOperationStatus | New, Processing, Completed, Failed |
| Output (response) | operationName | OperationName | Undefined, Register, Submit, Import |
GET /v1/conversion/orders/{orderId}
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | status | OrderStatus | Processing, Completed, Failed |
| Output (response) | origin | OrderOrigin | Participant, Admin, ForcedReconversion |
The submission endpoint POST /v1/conversion/orders returns no response body, so it publishes no response enumerations. The tables above cover the three calls that read order state.
GET /v1/conversion/orders
const query = new URLSearchParams({
fromWallet: sourceWallet.id,
toWallet: destinationWallet.id,
financialSecurityIds: selectedSecurity.id,
status: 'Processing',
offset: '0',
count: '20'
});
const ordersResponse = await fetch(`${baseUrl}/v1/conversion/orders?${query}`, {
headers: { 'Authorization': `Bearer ${access_token}` }
});
const existingOrders: OrderResponse[] = await ordersResponse.json();POST /v1/conversion/orders
const idempotencyKey = generateIdempotencyKey();
const orderResponse = await fetch(`${baseUrl}/v1/conversion/orders`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json',
'X-Idempotency-Key': idempotencyKey
},
body: JSON.stringify({
financialSecurityId: selectedSecurity.id,
fromWalletId: sourceWallet.id,
toWalletId: destinationWallet.id,
activityType: '040',
quantity: '500'
})
});
// 202 Accepted with no response body. Retain idempotencyKey for the async query.
if (orderResponse.status !== 202) {
throw new Error('Conversion order was not accepted');
}POST /v1/conversion/async-operations/query
const asyncResponse = await fetch(`${baseUrl}/v1/conversion/async-operations/query`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
idempotencyKeys: [idempotencyKey],
offset: 0,
count: 10
})
});
const operations: AsyncOperationResponse[] = await asyncResponse.json();
const orderId = operations[0]?.resourceId;GET /v1/conversion/orders/{orderId}
const detailResponse = await fetch(`${baseUrl}/v1/conversion/orders/${orderId}`, {
headers: { 'Authorization': `Bearer ${access_token}` }
});
const orderDetail: OrderDetailResponse = await detailResponse.json();
// orderDetail.status === 'Processing'GET /v1/conversion/orders
[
{
"id": "order-id",
"symbol": "EXMPL",
"cusip": "037833100",
"fromWallet": { "id": "source-wallet-id", "name": "Participant Classic Account", "walletAddress": "00002667-10" },
"toWallet": { "id": "destination-wallet-id", "name": "First Bank EVM Wallet", "walletAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" },
"quantity": 500,
"status": "Processing",
"errorMessage": null,
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z",
"activityType": "040",
"origin": "Participant"
}
]POST /v1/conversion/orders returns 202 Accepted with an empty body.
POST /v1/conversion/async-operations/query
[
{
"id": "async-operation-id",
"idempotencyKey": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"objectKind": "Order",
"status": "Completed",
"operationName": "Submit",
"resourceId": "order-id",
"resourceUrl": "/v1/conversion/orders/order-id",
"errorCode": null,
"errorMessage": null,
"asOfDate": "2026-01-01T00:00:00Z"
}
]GET /v1/conversion/orders/{orderId}
{
"orderId": "order-id",
"participant": { "id": "participant-id", "participantNumber": "00002667" },
"financialSecurityInfo": { "cusip": "037833100", "security": "Example Security" },
"fromWallet": { "id": "source-wallet-id", "name": "Participant Classic Account", "walletAddress": "00002667-10" },
"toWallet": { "id": "destination-wallet-id", "name": "First Bank EVM Wallet", "walletAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" },
"quantity": 500,
"submittedBy": "SA-ConversionBot",
"status": "Processing",
"errorMessage": null,
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z",
"activityType": "040",
"fromTransactionId": null,
"toTransactionId": null,
"check": { "status": "Passed" },
"origin": "Participant"
}interface OrderResponse {
id: string;
symbol?: string;
cusip?: string;
fromWallet: WalletRefResponse;
toWallet: WalletRefResponse;
quantity: number;
status: string;
errorMessage?: string;
createdAt: string;
obac?: AccessControlInfoResponse;
activityType?: string;
updatedAt?: string;
origin?: string;
}
interface AsyncOperationResponse {
id: string;
idempotencyKey: string;
objectKind: string;
status: string;
operationName: string;
resourceId?: string;
resourceUrl?: string;
errorCode?: string;
errorMessage?: string;
asOfDate: string;
}
interface OrderDetailResponse {
orderId: string;
participant: ParticipantResponse;
financialSecurityInfo?: OrderFinancialSecurityInfo;
fromWallet: WalletRefResponse;
toWallet: WalletRefResponse;
quantity: number;
submittedBy?: string;
submitterEmail?: string;
submitterComment?: string;
status: string;
errorMessage?: string;
createdAt: string;
updatedAt?: string;
activityType?: string;
fromTransactionId?: string;
toTransactionId?: string;
check: CheckInfoResponse;
origin?: string;
}Conversion direction must move between DTC_Classic and non-Classic wallets. Orders can be submitted Monday-Friday, 02:00-18:15 ET, with operational-hours enforcement server-side. Query the orders list before submitting to detect whether a prior submission with the same intent already exists, filtering on fromWallet, toWallet, financialSecurityIds, or status.
Handle 400 validation errors, 403 permission or lockout failures, 409 duplicate idempotency key, 422 business rule violations, and 5xx server errors. Submission does not execute the conversion synchronously; a 202 Accepted response confirms only that the order was queued for processing. Treat an async operation status of Failed as a submission failure and surface errorCode and errorMessage.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request, missing X-Idempotency-Key, or quantity of zero | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Security, wallet, or order identifier not found | Surface not found. Do not create a replacement order. |
| 409 | Duplicate X-Idempotency-Key | Treat the order as already submitted. Query the async operation with the same key to resolve the existing order identifier. |
| 422 | Business rule violation such as invalid conversion direction, ineligible security, ineligible wallet, or submission outside operational hours | Surface the specific rule violation. Do not retry until the input is corrected. |
| 500, 503 | Service failure | Retry with the same X-Idempotency-Key, maximum three attempts. |
The submission POST is protected by X-Idempotency-Key. Retrying with the same key is safe and will not create duplicate orders. Do not generate a new key on retry, because the key is also the lookup value for the async operation query. The async operation query and the order detail retrieval are read-only and safe to retry.
Demonstrate that a customer integration can execute the complete conversion order lifecycle: authenticate with OAuth 2.0 Client Credentials, load order, security, and wallet reference data, validate security and wallet eligibility, submit a conversion order, enforce idempotency controls, track asynchronous processing, correlate the async operation to the resulting order, retrieve final order detail, monitor lifecycle progression, and reconstruct the transaction audit trail. Unlike Account Management and Wallet Management, this certification validates both retrieval operations and transactional business processes.
Authenticate, load reference data in parallel, validate eligibility, submit, then track the order asynchronously to a terminal state.
OAuth 2.0 Client Credentials against /connect/token.
Orders, securities, and wallets in parallel, plus issue type, issue sub-type, and ledger filters.
Security status equals Active.
Wallet state equals Idle and conversionEligible is true.
POST /v1/conversion/orders returns 202 Accepted with no body.
Query by X-Idempotency-Key until a terminal status.
resourceId resolves the order identifier.
GET /v1/conversion/orders/{orderId}.
Processing to Completed, then reconstruct the audit trail.
| Rule | Requirement |
|---|---|
| Security Eligibility | Known security states are Onboarding, Active, Pause, and Failed. Only Active securities are eligible for conversion-order creation. |
| Wallet Eligibility | Known wallet states are Idle, Registering, FailedCompliance, and Failed. Only wallets that are Idle and conversion eligible may be used. |
| Conversion Direction | Conversion must occur between DTC Classic and digital wallets. |
| Quantity Validation | Quantity must be greater than zero. |
| Idempotency | Every submission must include X-Idempotency-Key. The same key must remain traceable throughout asynchronous processing. |
| Asynchronous Processing | Order creation returns HTTP 202 Accepted. Completion is determined through async operation tracking, not from the submission response. |
| Operational Hours | Monday to Friday, 02:00 ET to 18:15 ET. Enforcement is server-side. |
const baseUrl = "<base-url>";
const clientId = process.env.CLIENT_ID!;
const clientSecret = process.env.CLIENT_SECRET!;
const scope = process.env.CONVERSION_SCOPE!;async function authenticate() {
const response = await fetch(`${baseUrl}/connect/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: clientId,
client_secret: clientSecret,
scope
})
});
if (!response.ok) {
throw new Error("Authentication failed");
}
return response.json();
}
async function loadReferenceData(accessToken: string) {
const [ordersResponse, securitiesResponse, walletsResponse] = await Promise.all([
fetch(`${baseUrl}/v1/conversion/orders`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v1/conversion/securities`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v1/conversion/wallets`, { headers: { Authorization: `Bearer ${accessToken}` } })
]);
return {
orders: await ordersResponse.json(),
securities: await securitiesResponse.json(),
wallets: await walletsResponse.json()
};
}
async function loadFilterData(accessToken: string) {
const [issueTypesResponse, issueSubTypesResponse, ledgersResponse] = await Promise.all([
fetch(`${baseUrl}/v1/conversion/securities/issue-types`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v1/conversion/securities/issue-subtypes`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v1/tracking/networks`, { headers: { Authorization: `Bearer ${accessToken}` } })
]);
return {
issueTypes: await issueTypesResponse.json(),
issueSubTypes: await issueSubTypesResponse.json(),
ledgers: await ledgersResponse.json()
};
}
function generateIdempotencyKey() {
return crypto.randomUUID();
}
async function queryOperation(accessToken: string, idempotencyKey: string) {
const response = await fetch(`${baseUrl}/v1/conversion/async-operations/query`, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ idempotencyKeys: [idempotencyKey], offset: 0, count: 10 })
});
const [operation] = await response.json();
return operation;
}
async function getOrder(accessToken: string, orderId: string) {
const response = await fetch(`${baseUrl}/v1/conversion/orders/${orderId}`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) {
throw new Error(`Order retrieval failed with status ${response.status}`);
}
return response.json();
}Verify that the integration can obtain an access credential using the OAuth 2.0 Client Credentials grant. The credential proves the caller's identity and must be supplied as a bearer credential on every subsequent call in this workflow.
const token = await authenticate();
const accessToken = token.access_token;The response returns access_token, token_type, expires_in, and scope. The credential is usable on a subsequent API call.
HTTP 200; credential issued and usable.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid client credentials or malformed grant request | Correct the credentials. Do not retry with the same values. |
| 403 | Requested scope not granted to the client | Surface the scope failure. Do not retry. |
| 500, 503 | Identity service failure | Retry with exponential backoff, maximum three attempts. |
Verify that all prerequisite data loads successfully. Order, security, and wallet inventories supply the order inputs; issue type, issue sub-type, and ledger reference data supply the filter context.
const { orders, securities, wallets } = await loadReferenceData(accessToken);
const { issueTypes, issueSubTypes, ledgers } = await loadFilterData(accessToken);Order inventory returned. Security inventory returned. Wallet inventory returned. Issue type reference data returned. Issue sub-type reference data returned. Ledger network data returned.
HTTP 200 on each call; all six data sets available for downstream steps.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid access credential | Re-authenticate, then retry once. |
| 403 | Client lacks the required permission scope | Surface access denied. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff. Each call fails independently, so present a partial state rather than blocking the whole load. |
Verify that a valid conversion security can be identified from the security inventory loaded in Step 2.
const security = securities.find(security => security.status === "Active");The security exists and carries CUSIP, issuer, issue type, issue sub-type, restrictions, and token network information. Status equals Active. Securities in Onboarding, Pause, or Failed status are not eligible.
Eligible security identified.
This step performs no API calls. If no Active security is found, the integration must block order submission rather than proceeding with an ineligible security.
Verify that suitable source and destination wallets can be selected from the wallet inventory loaded in Step 2.
const eligibleWallets = wallets.filter(
wallet => wallet.state === "Idle" && wallet.conversionEligible === true
);The wallet exists, state equals Idle, conversionEligible equals true, network information is present, and no failure state is set. A wallet that satisfies only one of the two eligibility conditions is not a valid candidate. Wallets in Registering, FailedCompliance, or Failed state are not eligible.
Eligible wallets identified.
This step performs no API calls. If no wallet is both Idle and conversion eligible, the integration must block order submission rather than proceeding with an ineligible wallet.
Verify that a conversion order can be submitted with a valid idempotency key and accepted for asynchronous processing.
const idempotencyKey = generateIdempotencyKey();
const response = await fetch(`${baseUrl}/v1/conversion/orders`, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
"X-Idempotency-Key": idempotencyKey
},
body: JSON.stringify({
financialSecurityId: security.id,
fromWalletId: sourceWallet.id,
toWalletId: destinationWallet.id,
quantity: "100",
activityType: "040"
})
});HTTP 202 returned. The request is accepted and no validation error is returned. No response body is expected, so the order identifier is not available at this point. Retain idempotencyKey for the async operation query.
HTTP 202 Accepted with no response body.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request, missing X-Idempotency-Key, or quantity of zero | Correct the request. Do not retry as-is. |
| 403 | Client lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 409 | Duplicate X-Idempotency-Key | Treat the order as already submitted. Query the async operation with the same key to resolve the existing order. |
| 422 | Business rule violation such as invalid direction, ineligible security, ineligible wallet, or submission outside operational hours | Surface the specific rule violation. Do not retry until the input is corrected. |
| 500, 503 | Service failure | Retry with the same X-Idempotency-Key, maximum three attempts. |
Verify that resubmitting an identical request with the same idempotency key does not create a duplicate order.
Submit the same order request twice using the same X-Idempotency-Key.
A duplicate order is not created, idempotency is maintained, and the operation remains traceable under the original key.
Duplicate processing prevented.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 409 | Duplicate X-Idempotency-Key | Treat as already submitted. Reconcile against the existing order rather than resubmitting. |
| 400 | X-Idempotency-Key omitted entirely | Submission rejected. Add the header before retrying. |
Verify that asynchronous operations can be monitored using the idempotency key retained at submission.
const operation = await queryOperation(accessToken, idempotencyKey);The operation returns id, idempotencyKey echoing the submitted key, objectKind, status, operationName, and asOfDate. Known status values are New, Processing, Completed, and Failed. resourceId populates once processing begins.
HTTP 200; async operation successfully tracked.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid access credential | Re-authenticate, then retry once. |
| 500, 503 | Service failure | Retry with exponential backoff. The query is read-only and safe to repeat. |
Verify that an async operation can be correlated to the order it produced.
const operation = await queryOperation(accessToken, idempotencyKey);
const order = await getOrder(accessToken, operation.resourceId);resourceId is populated, resourceUrl is populated, the referenced order exists, and the order is retrievable.
HTTP 200; async operation successfully correlated to an order.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 404 | resourceId references an order that cannot be retrieved | Surface not found. Do not create a replacement order. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Verify that final order detail can be accessed once the order identifier is known.
const orderDetail = await getOrder(accessToken, operation.resourceId);The response carries order identifier, status, participant information, transaction information, and audit timestamps.
HTTP 200; order detail successfully retrieved.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid access credential | Re-authenticate, then retry once. |
| 404 | Order identifier not found | Surface not found. Do not create a replacement order. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Verify that lifecycle transitions can be monitored through to a terminal state.
Valid states are Processing, Completed, and Failed. Status progression is visible, a terminal state is reached, and the final state is recorded. Failed is terminal and must be surfaced with errorMessage rather than resubmitted.
HTTP 200; current order status returned and reportable.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid access credential | Re-authenticate, then retry once. |
| 404 | Order identifier not found | Surface not found. Do not create a replacement order. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Verify that the complete transaction history can be reconstructed from the artifacts produced across the workflow.
The order identifier is traceable, the idempotency key is traceable, the async operation is traceable, audit timestamps are available, and transaction identifiers are available.
End-to-end audit trace established.
This step performs no additional API calls. It relies on the artifacts captured in Steps 5 through 10. If any link in the chain cannot be reconstructed, the audit trace is incomplete and the workflow must be treated as unverified.
Execute the complete workflow from authentication through audit validation in a single uninterrupted run.
Authentication PASS
Reference Data PASS
Security Validation PASS
Wallet Validation PASS
Order Submission PASS
Idempotency PASS
Async Tracking PASS
Correlation PASS
Order Retrieval PASS
Lifecycle PASS
Audit PASSEach constituent call returns its expected success code.
Complete workflow executed and every stage verified.
| ID | Scenario | HTTP | Expected result |
|---|---|---|---|
| NT-1 | Invalid client credentials | 400 | Authentication rejected. |
| NT-2 | Invalid security | 422 | Order rejected. |
| NT-3 | Ineligible wallet | 422 | Order rejected. |
| NT-4 | Missing idempotency key | 400 | Request rejected. |
| NT-5 | Expired access credential | 401 | Authorization failure; re-authentication required. |
| NT-6 | Async processing failure | — | Async operation returns Failed status with errorCode and errorMessage present. Not an HTTP error condition. |
| NT-7 | Invalid order retrieval | 404 | Order not found; error handled without creating a replacement order. |
| NT-8 | Service unavailable | 503 | Retry attempted, failure reported, workflow stops safely. |
The customer must demonstrate authentication, reference-data retrieval, active-security validation, wallet eligibility validation covering both idle state and the conversion-eligible flag, conversion-order submission, idempotency compliance, async-operation monitoring, async-to-order correlation, final-order retrieval, lifecycle monitoring, audit validation, required negative-test handling, and end-to-end workflow execution.
Corporate Actions workflows support discovery, filtering, and detail inspection of corporate action events. The initial load retrieves events, event type taxonomy, and securities filters in parallel. Event detail is retrieved from a single endpoint and includes classification, security, date, DTC mandatory, and support context.
/connect/token with grant_type=urn:dtcc:params:oauth:grant-type:service-account-credentials, type=conveyance, entity context, tenant context via acr_values=tenant:{tenantId}, and service-account credentials. Downstream API calls use Authorization: Bearer {access_token}.A condensed view of the API call sequence, dependencies, and branch rules.
POST /connect/token
Obtain service-account token.
GET /v1/corporate-actions
Retrieve paginated events.
GET /v2/corporate-actions/event-typesGET /v1/conversion/securities
Load in parallel.
GET /v2/corporate-actions/{id}
Retrieve full event detail.
Interpret status, category, DTC mandatory classification, support flag, and relevant core dates.
GET /v2/corporate-actions/{id}, including security data, event classification, core dates, DTC mandatory classification, support status, and payout-related metadata.Fetches the events list alongside event taxonomy and securities filter options.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| searchFor | query | string | Optional | Free-text term matched against event and security fields to narrow the result set. |
| orderBy | query | EventFields enum | Optional | Field the results are sorted on, such as last-updated timestamp, payable date, or business event number. |
| sortOrder | query | SortOrder enum | Optional | Direction applied to the chosen sort field, either ascending or descending. |
| ids / eventIds | query | string[] | Optional | Limits results to specific records, referenced either by the platform's internal record key or by the business-facing event number; up to 50 values. |
| eventTypes | query | EventTypeEnumeration[] | Optional | Limits results to one or more high-level corporate action classifications, such as a cash dividend or a reorganization; up to 50 values. |
| subEventTypes | query | int32[] | Optional | Limits results to the finer classifications nested beneath a high-level type, such as a deemed dividend; up to 50 values. |
| eventSecurityIds | query | string[] | Optional | Limits results to events affecting particular securities, referenced by their platform identifier; up to 50 values. |
| status | query | EventStatusEnumeration[] | Optional | Limits results to events sitting in particular approval or cancellation states; up to 5 values. |
| offset / count | query | int32 | Optional | Controls which slice of the result set is returned, where offset is the starting position and count is the number of records per page. |
GET /v1/corporate-actions
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | eventType | EventTypeEnumeration | AutomaticDividendReinvestment, CapitalGainsDistribution, CashDividend, CDEarlyRedemption, Change, Consent, Conversion, Default, Distribution, DividendWithOption, DutchAuction, ExchangeOffer, FinalPaydown, FullCall, FullPrerefunding, GeneralInformation, Interest, Liquidation, MandatoryExchange, MandatoryPut, Maturity, Meeting, Merger, NameChange, OddLotOffer, PartialCall, PartialDefeasance, PartialMandatoryPut, PartialPrerefunding, PayInKind, PlanOfReorganization, Principal, Put, RedemptionOfRights, RedemptionOfWarrants, Reorganization, ReturnOfCapital, ReverseStockSplit, RightsDistribution, RightsSubscription, SaleOfRights, SecuritySeparation, SpecialDividend, SpinOff, StockDividend, StockSplit, TaxEvent, TaxRefund, TenderOffer, Termination, WarrantsExercise, Worthless |
| Input (query) | status | EventStatusEnumeration | Approved, ConditionallyApproved, Incomplete, Cancelled, Deleted |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Input (query) | orderBy | EventFields | Id, EventId, EventType, SubEventType, Status, Security, SecurityId, PositionCaptureDate, PayableDate, AnticipatedPayDate, InstructionExpirationDate, CreatedAt, UpdatedAt |
| Output (response) | eventType | EventTypeEnumeration | Same values as listed above. |
| Output (response) | subEventType | SubEventTypeEnumeration | None, DRIPDTCOnly, OptOutDTCOnly, Domicile, DomicileNewCUSIP, DomicilePresentationRequired, DomicileNewCUSIPPresentationRequired, WithPayout, WithoutPayout, FinalPayment, InterimPayment, TaxCredit, Consent, A144, CashAndSecurities, RegS, Unwind, Conversion, ImportantNotice, DayExemptionQualifiedNotice, BasedOnRecordDateHoldings, PresentationRequired, Retain, Securities, Annual, Extraordinary, General, Special, Cash, CUSIPChangePresentationRequired, NewCUSIP, Vote, MortgageBacked, SurvivorOptions, SPAC, SaleOfAssets, PhysicalRightsNotIssued, ADR, PoisonPill, CDeemedDividend, DividendEquivalentPayment, ExcessOfCumulativeNetIncome, SClassifications1042, BidTenderSealedTender, CashInLieu, ConvertAndTender, MiniTender, OfferToPurchase, SelfTender, GDR, MeetingType |
| Output (response) | status | EventStatusEnumeration | Approved, ConditionallyApproved, Incomplete, Cancelled, Deleted |
| Output (response) | dtcMandatory | DtcMandatory | Mandatory, MandatoryWithOptions, Voluntary |
| Output (response) | eventCategory | EventCategory | InterestOnTreasury, MaturityOnTreasury, MandatoryCashDistribution, MandatorySecurityDistribution, MandatoryWithChoiceDistribution, MandatoryReorganization, VoluntaryReorganization, Meetings |
GET /v2/corporate-actions/event-types
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | eventType | EventTypeEnumeration | Same values as listed for GET /v1/corporate-actions above. |
| Output (response) | subEventType | SubEventTypeEnumeration | Same values as listed for GET /v1/corporate-actions above. |
GET /v1/conversion/securities
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Input (query) | orderBy | FinancialSecurityFields | CUSIP, Description, Issuer |
| Input (query) | sortOrder | SortOrder | Ascending, Descending |
| Output (response) | status | FinancialSecurityStatus | Onboarding, Active, Pause, Failed |
| Output (response) | processingState | ProcessingStates | Idle, Registering, FailedCompliance, Failed |
const [eventsResponse, eventTypesResponse, securitiesResponse] = await Promise.all([
fetch(`${baseUrl}/v1/corporate-actions?orderBy=UpdatedAt&sortOrder=Descending&count=25&offset=0`, {
headers: { 'Authorization': `Bearer ${access_token}` }
}),
fetch(`${baseUrl}/v2/corporate-actions/event-types`, {
headers: { 'Authorization': `Bearer ${access_token}` }
}),
fetch(`${baseUrl}/v1/conversion/securities`, {
headers: { 'Authorization': `Bearer ${access_token}` }
})
]);
const events = await eventsResponse.json();[
{ "id": "event-record-id", "eventId": "123456", "eventTypeDescription": "Cash Dividend", "eventType": "CashDividend", "status": "Approved", "updatedAt": "2026-01-01T00:00:00Z", "security": { "id": "security-id", "cusip": "123456789", "name": "Example Security" } }
]interface CorporateActionEventListResponse {
id: string;
eventId: string;
eventTypeDescription: string;
eventType: string;
subEventTypeDescription: string;
subEventType: string;
status: string;
updatedAt: string | null;
security: { id: string; cusip: string; name: string };
}
interface EventTypePairResponse {
eventType: number;
eventTypeCode: string;
eventTypeDescription: string;
subEventType: number;
subEventTypeCode: string;
subEventTypeDescription: string;
}Approved, ConditionallyApproved, Incomplete, Cancelled, and Deleted.
Handle 401 by requesting a new JWT access credential and retrying once, 403 as lockout or missing permission, 400 as invalid filters, and 5xx with retry. If the event-type or securities call fails, disable the affected filter while keeping the events list usable.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Malformed request or invalid filter parameter | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Resource not found | Surface not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. Keep the workflow stable and disable only the affected filter. |
All three calls are read-only GETs and safe to retry on 5xx or network timeout.
Retrieves full detail for a specific corporate action event.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | Unique key of a single corporate action event, taken from the results of the event list call. |
GET /v2/corporate-actions/{id}
| Direction | Parameter / Field | Enum Name | Values |
|---|---|---|---|
| Output (response) | eventType | EventTypeEnumeration | AutomaticDividendReinvestment, CapitalGainsDistribution, CashDividend, CDEarlyRedemption, Change, Consent, Conversion, Default, Distribution, DividendWithOption, DutchAuction, ExchangeOffer, FinalPaydown, FullCall, FullPrerefunding, GeneralInformation, Interest, Liquidation, MandatoryExchange, MandatoryPut, Maturity, Meeting, Merger, NameChange, OddLotOffer, PartialCall, PartialDefeasance, PartialMandatoryPut, PartialPrerefunding, PayInKind, PlanOfReorganization, Principal, Put, RedemptionOfRights, RedemptionOfWarrants, Reorganization, ReturnOfCapital, ReverseStockSplit, RightsDistribution, RightsSubscription, SaleOfRights, SecuritySeparation, SpecialDividend, SpinOff, StockDividend, StockSplit, TaxEvent, TaxRefund, TenderOffer, Termination, WarrantsExercise, Worthless |
| Output (response) | subEventType | SubEventTypeEnumeration | None, DRIPDTCOnly, OptOutDTCOnly, Domicile, DomicileNewCUSIP, DomicilePresentationRequired, DomicileNewCUSIPPresentationRequired, WithPayout, WithoutPayout, FinalPayment, InterimPayment, TaxCredit, Consent, A144, CashAndSecurities, RegS, Unwind, Conversion, ImportantNotice, DayExemptionQualifiedNotice, BasedOnRecordDateHoldings, PresentationRequired, Retain, Securities, Annual, Extraordinary, General, Special, Cash, CUSIPChangePresentationRequired, NewCUSIP, Vote, MortgageBacked, SurvivorOptions, SPAC, SaleOfAssets, PhysicalRightsNotIssued, ADR, PoisonPill, CDeemedDividend, DividendEquivalentPayment, ExcessOfCumulativeNetIncome, SClassifications1042, BidTenderSealedTender, CashInLieu, ConvertAndTender, MiniTender, OfferToPurchase, SelfTender, GDR, MeetingType |
| Output (response) | status | EventStatusEnumeration | Approved, ConditionallyApproved, Incomplete, Cancelled, Deleted |
| Output (response) | dtcMandatory | DtcMandatory | Mandatory, MandatoryWithOptions, Voluntary |
| Output (response) | eventCategory | EventCategory | InterestOnTreasury, MaturityOnTreasury, MandatoryCashDistribution, MandatorySecurityDistribution, MandatoryWithChoiceDistribution, MandatoryReorganization, VoluntaryReorganization, Meetings |
| Output (response) | positionProcessingStatus | PositionProcessingStatus | New, Processed, Failed |
const eventDetailResponse = await fetch(
`${baseUrl}/v2/corporate-actions/${eventId}`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
if (!eventDetailResponse.ok) {
const error = await eventDetailResponse.json();
throw new Error(`Event detail request failed: ${error.ErrorCode} - ${error.ErrorMessage}`);
}
const eventDetail = await eventDetailResponse.json();{
"id": "event-record-id",
"eventId": "123456",
"eventGroup": "Distribution",
"eventType": "CashDividend",
"eventTypeDescription": "Cash Dividend",
"subEventType": "CDeemedDividend",
"subEventTypeDescription": "305C - Deemed Dividend",
"status": "ConditionallyApproved",
"category": "MandatoryCashDistribution",
"isSupported": false,
"dtcMandatory": "Mandatory",
"security": { "id": "security-id", "cusip": "46625H202", "name": "Example Security", "issuerDescription": "Example Issuer", "assetClass": "Equity", "assetType": "Common Stock", "ticker": "EX" },
"coreDates": { "exDate": "2026-06-24T00:00:00Z", "recordDate": "2026-06-24T00:00:00Z", "declaredPayableDate": "2026-06-24T00:00:00Z", "allocationDateTime": null }
}interface CorporateActionEventResponse {
id: string;
security: { id: string; cusip: string; name: string; issuerDescription: string; assetClass: string; assetType: string; ticker: string };
eventId: string;
eventGroup: string;
eventType: string;
eventTypeDescription: string;
subEventType: string;
subEventTypeDescription: string;
status: string;
category: string;
isSupported: boolean;
dtcMandatory: string;
reconversionDate: string | null;
coreDates: Record<string, string | null>;
}The event detail response includes security information, event classification, status, category, DTC mandatory classification, support indicator, reconversion date, and coreDates. No separate entitlements endpoint is needed for the workflow described in the source material.
Handle 401 as an expired credential, 403 as lockout or missing detail permission, 404 as an invalid or deleted event, 400 as an invalid event ID format, and 500 with retry. The response body carries ErrorCode and ErrorMessage, which should be surfaced rather than discarded.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid event identifier format | Correct the request. Do not retry as-is. |
| 401 | JWT access credential missing, expired, or invalid | Request a new JWT access credential, then retry once. |
| 403 | Service account lacks the required permission, or the account is locked | Surface access denied. Do not retry. |
| 404 | Invalid or deleted event | Surface event not found. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Read-only GET; safe to retry on 5xx or network timeout. Use exponential backoff with a maximum of three retries.
| Category | Relevant Core Dates |
|---|---|
InterestOnTreasury | declaredPayableDate, allocationDateTime |
MaturityOnTreasury | declaredPayableDate, allocationDateTime |
MandatoryCashDistribution | exDate, recordDate, dtcPositionCaptureDate or captureDate, declaredPayableDate, anticipateDate, allocationDateTime |
MandatorySecurityDistribution | exDate, recordDate, positionCaptureDate, allocationDateTime |
MandatoryWithChoiceDistribution | exDate, recordDate, positionCaptureDate, instructionExpiration, allocationDateTime |
MandatoryReorganization | effectiveDateCompany, positionCaptureDate, allocationDateTime, reconversionDate |
VoluntaryReorganization | dtcInstructionExpirationDateTime, positionCaptureDate, allocationDateTime |
Meetings | meetingDate |
| Value | Meaning |
|---|---|
Mandatory | Participation is automatic; no election required. |
MandatoryWithOption | Mandatory but participants may choose from options. |
Voluntary | Participation requires explicit election by the holder. |
This certification verifies both API connectivity and the customer's ability to correctly interpret corporate action event data.
Authenticate, load events, load event types and securities in parallel, inspect the event, then apply context.
Obtain a JWT access credential using SA-CorporateActionsBot.
GET /v1/corporate-actions
event-types plus securities in parallel.
GET /v2/corporate-actions/{id}
Status, category, DTC classification, and core dates.
GET /v2/corporate-actions/{id}. No additional entitlement endpoint is required.| Rule | Requirement |
|---|---|
| Parallel Loading | Retrieve events, event types, and securities concurrently. |
| Supported Statuses | Approved, ConditionallyApproved, Incomplete, Cancelled, Deleted. |
| Detail Retrieval | All detail information is retrieved from GET /v2/corporate-actions/{id}. |
| Context Interpretation | Customers must correctly apply status, category, DTC mandatory classification, support indicator, and core dates. |
Tenant ID, service account, service account password, base URL, a known corporate action event, and securities access. Required endpoints: /connect/token, /v1/corporate-actions, /v2/corporate-actions/event-types, /v1/conversion/securities, /v2/corporate-actions/{id}.
const tenantId = "<tenant-id>";
const baseUrl = "<base-url>";
const username = "SA-CorporateActionsBot";
const password = process.env.SERVICE_ACCOUNT_PASSWORD!;async function loadCorporateActionsData(accessToken: string) {
const [eventsResponse, eventTypesResponse, securitiesResponse] = await Promise.all([
fetch(`${baseUrl}/v1/corporate-actions`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v2/corporate-actions/event-types`, { headers: { Authorization: `Bearer ${accessToken}` } }),
fetch(`${baseUrl}/v1/conversion/securities`, { headers: { Authorization: `Bearer ${accessToken}` } })
]);
return {
events: await eventsResponse.json(),
eventTypes: await eventTypesResponse.json(),
securities: await securitiesResponse.json()
};
}
async function getEventDetail(accessToken: string, eventId: string) {
const response = await fetch(`${baseUrl}/v2/corporate-actions/${eventId}`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Event detail failed: ${error.ErrorCode} - ${error.ErrorMessage}`);
}
return response.json();
}This step validates that the integration can obtain a JWT access credential from the Identity Server using service account credentials. The JWT access credential proves the caller's identity and must be supplied as a bearer credential on every subsequent API call in this workflow.
HTTP 200; JWT access credential returned; credential accepted by downstream APIs.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid credentials | Surface authentication rejected. Do not retry with the same credentials. |
| 500, 503 | Identity Server failure | Retry with exponential backoff, maximum three attempts. |
Verify the integration can retrieve a paginated corporate action event inventory with statuses and event identifiers populated.
const data = await loadCorporateActionsData(accessToken);Events returned; pagination supported; statuses populated; event identifiers returned.
HTTP 200; corporate action inventory loaded successfully.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid filter parameters | Correct the request. Do not retry as-is. |
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 403 | Missing permission | Surface access denied. Do not retry. |
| 500, 503 | Service failure | Retry with exponential backoff, maximum three attempts. |
Verify the integration can retrieve the event type and sub-event type taxonomy used for hierarchical event filtering.
Event types returned; sub-event types returned; hierarchy available.
HTTP 200; event taxonomy successfully loaded.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 500, 503 | Event-type service unavailable | Filter data unavailable; display a meaningful error and keep the workflow stable. |
Verify the integration can retrieve securities reference data, including CUSIPs and support flags, for filtering corporate action events.
Security identifiers returned; CUSIPs returned; support flags returned.
HTTP 200; security filtering possible.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 401 | Expired or invalid JWT access credential | Re-authenticate, then retry once. |
| 500, 503 | Securities service unavailable | Security filter unavailable; display a meaningful error and keep the workflow stable. |
Verify the integration can narrow the event inventory to a relevant subset using status, event type, sub-event type, security, and search text.
const approvedEvents = events.filter(
event => event.status === "Approved"
);Successful filtering by status, event type, sub-event type, security, and search text.
Relevant events identified.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid filter parameters | Validation error. Correct the filter values before retrying. |
Verify the integration can retrieve full event detail from the single detail endpoint, including security, category, status, classification, and core dates.
const detail = await getEventDetail(accessToken, eventId);Security returned; category returned; status returned; DTC classification returned; core dates returned.
HTTP 200; event detail successfully retrieved.
| HTTP | Condition | Expected integration behavior |
|---|---|---|
| 400 | Invalid event identifier format | Correct the request. Do not retry as-is. |
| 404 | Invalid event ID; event not found | Surface event not found. Do not retry. |
| 500, 503 | Event detail service failure | Invoke retry logic with exponential backoff and handle the failure gracefully. |
Verify the integration derives correct business context from the returned category, status, support indicator, and DTC classification.
if (detail.dtcMandatory === "Voluntary") {
console.log("Election Required");
}Interpret category, status, support flag, and DTC classification.
Business context successfully derived.
This step performs no API calls. If a required context field is absent from the event detail response, treat the step as failed rather than applying a default classification.
Verify the integration identifies the correct set of lifecycle dates for each corporate action category it processes.
| Category | Required Dates |
|---|---|
InterestOnTreasury | declaredPayableDate, allocationDateTime |
MaturityOnTreasury | declaredPayableDate, allocationDateTime |
MandatoryCashDistribution | exDate, recordDate, captureDate, declaredPayableDate, anticipateDate, allocationDateTime |
Meetings | meetingDate |
Correctly identify the relevant dates for at least one event available in each category.
The correct set of lifecycle dates is identified for each category present in the test dataset.
This step performs no API calls. If a required date is null for a category that mandates it, surface the gap rather than substituting a placeholder date.
Verify the integration correctly classifies each event as Mandatory, MandatoryWithOption, or Voluntary and acts on whether an election is required.
| Value | Meaning |
|---|---|
Mandatory | Participation automatic. |
MandatoryWithOption | Options available to holder. |
Voluntary | Election required. |
The customer correctly classifies events using the returned values.
Each event is classified as Mandatory, MandatoryWithOption, or Voluntary, and election requirements are applied accordingly.
This step performs no API calls. An unrecognized dtcMandatory value must be surfaced as an unhandled classification rather than defaulted to Mandatory.
Execute the complete corporate actions workflow in a single run to confirm every stage succeeds in sequence.
async function executeWorkflow() {
const token = await authenticate();
const { events, eventTypes, securities } = await loadCorporateActionsData(token);
const selectedEvent = events[0];
const detail = await getEventDetail(token, selectedEvent.id);
return { events, eventTypes, securities, detail };
}Authentication PASS
Load Events PASS
Load Event Types PASS
Load Securities PASS
Filter Events PASS
Retrieve Detail PASS
Apply Context PASS
Workflow Complete PASSEach constituent call returns its expected success code.
| ID | Scenario | HTTP | Expected result |
|---|---|---|---|
| NT-1 | Invalid Credentials | 400 | Authentication rejected. |
| NT-2 | Expired Credential | 401 | Re-authentication required. |
| NT-3 | Invalid Event ID | 404 | Event not found. |
| NT-4 | Missing Permission | 403 | Access denied. |
| NT-5 | Invalid Filter Parameters | 400 | Validation error. |
| NT-6 | Event-Type Service Unavailable | 500, 503 | Filter data unavailable; meaningful error displayed; workflow remains stable. |
| NT-7 | Securities Service Unavailable | 500, 503 | Security filter unavailable; meaningful error displayed; workflow remains stable. |
| NT-8 | Event Detail Service Failure | 500, 503 | Retry logic invoked; graceful failure handling. |
The customer must demonstrate authentication, event retrieval, event-type retrieval, securities retrieval, event filtering, event-detail retrieval, context interpretation, category-date interpretation, DTC classification interpretation, negative-test handling, and end-to-end workflow execution.
This tab records every change applied to this reference guide. Each version card carries the date the change was applied, and lists the changes grouped by the tab or section of the site affected.
/v1/networks/ledgers to /v1/tracking/networks to match the API specification.name, displayName, networkStatus, nodeFormats, and listenerEnabled, and fixed the sample request filter accordingly.status to networkStatus and removed the nodeStatus / NetworkNodeStatus row, which the specification does not define.Declined from the lifecycle states, leaving Processing, Completed, and Failed.queryOperation and getOrder helper functions, which the source document referenced without defining, and changed the correlation step to query by idempotency key rather than by an operation identifier the workflow never produces.loadFilterData and extended Step 2 to call it, so the issue type, issue sub-type, and ledger endpoints remain within the certification.Offset and Count on the orders list, the securities list, the wallets list, and the async operation query.type on the account balances card.limit and offset unchanged on the account hierarchy summary and account activities cards.type and state, matching the API integration guide, and removed the note that recorded the earlier naming discrepancy.Offset and Count.offset and count unchanged.Deleting from the ProcessingStates values in all five places it appeared, covering both wallet and security rows so the enumeration keeps a single definition.X-Idempotency-Key throughout.COE_SCOPE environment variable reference with API_SCOPE.Offset and Count query parameters, the X-Paging response headers, endpoint support, and iteration guidance.Offset and Count in the request body rather than the query string, an exception to the model's general rule.POST /v1/conversion/orders returns 202 Accepted with no response body, so the order identifier is resolved by polling the async operation with the idempotency key retained at submission.GET /v1/conversion/orders, POST /v1/conversion/async-operations/query, and GET /v1/conversion/orders/{orderId}.asyncOperationStatus, objectKind, and operationName to the async operation query, and orderBy to the orders list.OrderOrigin enumeration with values Participant, Admin, and ForcedReconversion.conversionEligible true in addition to an Idle processing state, applied across the eligibility rules, the workflow summary, the key business rules, and the production certification criteria.resourceId before retrieving the order. Remaining certification steps are being regenerated.Failed to the FinancialSecurityStatus values published on the account balances card.FailedCompliance and Failed to the ProcessingStates values.type and state, while the guide follows the enumeration reference document naming.FinancialSecurityStatus and ProcessingStates value additions into the securities reference enumerations on the events card./v1/tracking/networks and /v1/conversion/clients.