DTCC Digital Assets

Digital Assets API Reference Guide

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.

Getting Started
One integration guide across the DTCC Digital Assets journey

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.

Base URLs:
EnvironmentIdentity (Authentication)Services
PSE (Pre-Production)https://api.pse.lds.dtcc-da.com/identityhttps://api.pse.lds.dtcc-da.com/services
Productionhttps://api.ledgerscan.dtcc-da.com/identity/https://api.ledgerscan.dtcc-da.com/services/
Authentication pattern: These workflows use the Service Account Credentials grant. The token request is sent to /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}.
Account ManagementAccount detail, hierarchy summary, access control metadata, locked operation handling, and on-chain account activities through the DTCC APIs.
Wallet ManagementWallet inventory, ledger/account reference data, and status tracking for wallet administration workflows.
Conversion OrdersRegistered securities, issue and ledger reference data, active security selection, idle wallet selection, order submission, and order lifecycle tracking.
Corporate ActionsEvent discovery, event type taxonomy, securities filtering, event detail, core dates by category, DTC mandatory classification, and status handling.
Guide Structure

Workflow-first organization

Each tab starts with a compact flow showing call ordering, parallel-load opportunities, branch behavior, and service dependencies before endpoint-level detail.

Integration Pattern

Service-account authentication

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.

Operational Readiness

Rules, status, and error handling

Each journey includes business rules, retry guidance, permission considerations, idempotency, async state tracking, and graceful degradation for reference-data failures.

Primary API Journeys

JourneyPrimary APIsPurpose
Account Management/connect/token, /v1/accounts/{accountId}, /v1/accounts/{accountId}/summary, /v1/accounts/{accountId}/activities, /v1/conversion/accounts/{accountId}/balancesRetrieve 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/clientsLoad 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.
How to use this guide: Start with the relevant tab for the implementation journey, review the compact flow, then use the searchable endpoint cards for request parameters, sample calls, response models, retry guidance, and service dependencies.
Certification

Workflow Certification Framework

CERT
Tokenization Service Workflow Certification Guide
Production Readiness Validation Framework

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.

Certification Focus

Focus Area

Workflow Execution

Complete the ordered sequence of steps that compose each production workflow.

Focus Area

Business-Rule Compliance

Apply the platform business rules that govern eligibility, direction, and validation.

Focus Area

Error Handling

Handle invalid credentials, expired credentials, access denials, and service failures.

Focus Area

Operational Readiness

Demonstrate production supportability across the certified workflows.

Focus Area

Production Supportability

Sustain and monitor operations after go-live without introducing risk.

Focus Area

Evidence Collection

Produce request logs, response payloads, and execution output as audit evidence.

Certification Philosophy

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.

Authenticate

Establish a valid session.

Retrieve Required Data

Load inputs for the workflow.

Apply Business Rules

Enforce platform constraints.

Execute Workflow Actions

Perform the operation.

Validate Outcomes

Confirm expected results.

Handle Failures

Manage error conditions.

Produce Evidence

Capture supporting audit artifacts.

AuthenticationData RetrievalBusiness RulesAction ExecutionOutcome ValidationFailure HandlingEvidence

Certification Portfolio

The following workflow certifications are currently included within the Tokenization Service certification framework.

Account ManagementSupports account discovery, hierarchy inspection, sub-account visibility, wallet visibility, activity retrieval, balance retrieval, and operational monitoring.
Wallet ManagementSupports wallet discovery, wallet inventory review, status monitoring, ledger lookup, and client reference lookup.
Conversion OrdersSupports security discovery, reference-data retrieval, wallet discovery, eligibility determination, conversion-order creation, and lifecycle monitoring.
Corporate ActionsSupports corporate-action discovery, event filtering, event inspection, event classification, lifecycle-date interpretation, and corporate-action monitoring.

Common Certification Requirements

All workflow certifications require demonstration of the following.

RequirementDetail
AuthenticationValid service account authentication.
Error HandlingInvalid credentials, expired credentials, access denied, invalid requests, not found conditions, and service failures.
Workflow CompletionAll required steps executed successfully.
AuditabilityRequest logs, response payloads, execution output, workflow results, and negative-test results.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request, invalid parameter, or invalid credentialsCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry 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.

Certification Framework Summary

Account ManagementWallet ManagementConversion OrdersCorporate Actions

These workflow certifications serve as the formal production-readiness gate for Tokenization Service integrations.

Pre-Implementation
Participant Setup & Onboarding

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.

Workflow Summary

A condensed view of the API call sequence, dependencies, and branch rules.

Collect Onboarding Inputs

Capture participant name, DTC account information, technical contact, entity administrator, and go-live inputs.

Initiate Onboarding

The Integration team uses the Operations Portal to initiate participant onboarding, validate onboarding inputs, and launch the provisioning workflow.

Provision Participant

Create the participant entity, DTCC standard account structure, provision wallets, assign controller permissions, create the participant administrator, send onboarding notifications, and activate the participant.

Readiness rule: to access APIs participants must provision and configure service accounts
Entity CreationAccount ProvisioningService AccountsProduction Activation
Onboarding Setup: Service accounts and Wallet Registration can only be set up by the participant through the UI. API-based service account and wallet registration setup is not available.
Category 1
Account Management

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.

Authentication pattern: These workflows use the Service Account Credentials grant. The token request is sent to /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}.

Workflow Summary

A condensed view of the API call sequence, dependencies, and branch rules.

Authenticate

POST /connect/token
Obtain a service-account bearer token.

Fetch account

GET /v1/accounts/{accountId}
Retrieve account and optional access control metadata.

Fetch hierarchy

GET /v1/accounts/{accountId}/summary
Retrieve child accounts and linked wallets.

Query activities

GET /v1/accounts/{accountId}/activities
Retrieve filtered on-chain activity from the DTCC APIs.

Degrade gracefully

Show partial account data if downstream hierarchy or activity services are unavailable.

Locked operation rule: When locked operations such as Updating or ChangeLinking are present, link/unlink and mutation actions should be treated as unavailable regardless of permission metadata.
Service AccountDTCC APIsAccess ControlDTCC APIs
GET
Get Account Detail
/v1/accounts/{accountId}

Retrieves account data and optional page-level access control permissions. This call confirms that the account exists and that the caller has access.

Request Parameters

ParameterLocationTypeRequiredDescription
accountIdpathstringYesThe account identifier
includeObacquerybooleanOptionalWhen true, includes access-control information

Sample Request

typescript
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();

Response Template

json
{
  "accountId": "account-id",
  "name": "Example Account",
  "externalId": null,
  "itemId": null,
  "accessControl": { "isController": true, "isShared": false, "hasShareRequest": false }
}

TypeScript Interface

typescript
interface AccountWithAccessControlResponse {
  accountId: string;
  name: string;
  externalId: string | null;
  itemId: string | null;
  accessControl: AccessControlInfo | null;
}
interface AccessControlInfo {
  isController: boolean;
  isShared: boolean;
  hasShareRequest: boolean;
}

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

Retry Guidance

Read-only GET; safe to retry on 5xx or network timeout. Do not retry credential requests on 4xx.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Get Account Hierarchy Summary
/v1/accounts/{accountId}/summary

Returns child accounts and linked wallets below a parent account for display and access-control interpretation.

Request Parameters

ParameterLocationTypeRequiredDescription
accountIdpathstring UUIDYesThe parent account identifier
includeObacquerybooleanYesAlways true to include access control metadata per item
limitqueryintegerOptionalPagination page size
offsetqueryintegerOptionalPagination offset
typequerystringOptionalFilter: Account or Wallet
searchquerystringOptionalSearch by name

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/accounts/{accountId}/summary

DirectionParameter / FieldEnum NameValues
Output (response)entityTypeAccountHierarchyEntityTypeWallet, Account
Output (response)trackingStatusTrackingStatusNone, Enabled, Disabled, Enabling, Disabling
Output (response)linkageStatusLinkageStatusLinking, Unlinking, Linked

Sample Request

typescript
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);

Response Template

json
[
  { "id": "account-1", "name": "Sub Account", "type": "Account", "lockedOperations": ["Updating"] },
  { "id": "wallet-1", "name": "Wallet A", "type": "Wallet", "walletDetails": { "address": "0x..." } }
]

TypeScript Interface

typescript
interface AccountSummary {
  id: string;
  name: string;
  type: 'Account' | 'Wallet';
  externalId?: string;
  lockedOperations?: string[];
  walletDetails?: { address: string };
  accessControl?: { isShared: boolean };
}

Error Handling

If the summary fetch fails, account data may still be shown while hierarchy detail is unavailable; present a partial state and a retry option.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

Retry Guidance

Read-only GET; safe to retry on 5xx or network timeout.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Get Account Activities
/v1/accounts/{accountId}/activities

Retrieves paginated on-chain activities with date range, activity type, network, source wallet, destination wallet, pagination, and sorting filters.

Request Parameters

ParameterLocationTypeRequiredDescription
accountIdpathstring UUIDYesParent or sub-account identifier
startDatequeryISO 8601 stringOptionalFilter activities from this date; defaults to the current week if omitted
endDatequeryISO 8601 stringOptionalFilter activities until this date; clamp future values to now
activityTypequerystringOptionalFilter by activity type
networkquerystringOptionalLedger network filter
fromWalletIdquerystring UUIDOptionalSource wallet filter
toWalletIdquerystring UUIDOptionalDestination wallet filter
limit / offsetqueryintegerOptionalPagination controls
sortBy / sortOrderquerystringOptionalSorting controls

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/accounts/{accountId}/activities

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending

Sample Request

typescript
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();

Response Template

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" }
}

TypeScript Interface

typescript
interface AccountActivitiesWithMetaDataApiModel {
  items: AccountActivitiesApiModel[];
  metadata: { asOfDate: string };
}

Activity Types

fee, payment, paymentreceived, mint, burn, debit, credit, freeze, unfreeze, partialfreeze, partialunfreeze, revoked, and clawedback.

Response Metadata

The response includes metadata with asOfDate, indicating the point-in-time represented by the activity data.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Continue to display account detail without activities.

Retry Guidance

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.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Get Account Balances
/v1/conversion/accounts/{accountId}/balances

Retrieves balance records for an account.

Request Parameters

ParameterLocationTypeRequiredDescription
accountIdpathstringYesIdentifier 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.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/conversion/accounts/{accountId}/balances

DirectionParameter / FieldEnum NameValues
Output (response)statusFinancialSecurityStatusOnboarding, Active, Pause, Failed
Output (response)typeWalletTypesInternal, Client

Sample Request

typescript
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();

Response Template

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"
  }
}

TypeScript Interface

typescript
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;
}

Response Metadata

The response includes metadata with asOfDate, indicating the point-in-time represented by the balance data.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

Retry Guidance

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.

Permissions & Scopes

Auth PatternOAuth 2.0 Client Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

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.

Under Construction: Service Account management APIs (create, update, delete service accounts) are under development and will be documented in a future version of this guide. Wallet registration is not available through APIs; wallet registration is performed through the UI.
Certification

Account Management Workflow Certification Test

CERT
Account Management Workflow Certification Test
Certification · v1 · Authenticate → Retrieve Account → Retrieve Hierarchy → Query Activity → Query Balances

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.

Certification Workflow

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.

Authenticate

Obtain a JWT access credential using SA-AccountBot.

Retrieve Account

Confirm the account identifier matches the request.

Retrieve Hierarchy

Retrieve child accounts and linked wallets.

Query Activity

Retrieve paginated activities with asOfDate.

Query Balances

Retrieve, reconcile, and interpret security-level balances.

Independent service failure: Account retrieval and activity retrieval fail independently. If activity retrieval fails, account data remains available and the integration must fail gracefully with a clear error message.
Separate grant for balances: Steps one through four use the Service Account Credentials grant. Step five uses the OAuth 2.0 Client Credentials grant and obtains its own credential, so the credential from step one cannot be reused.
AuthenticationAccount RetrievalHierarchyActivityBalances

Prerequisites

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.

Test Data

typescript
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!;

POST
Step 1 — Authentication
${baseUrl}/connect/token

Goal

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.

Procedure

typescript
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;
}

Expected Result

HTTP 200; JWT access credential returned; credential accepted by downstream APIs.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid credentials; invalid_clientSurface authentication rejected. Do not retry with the same credentials.
500, 503Identity Server failureRetry with exponential backoff, maximum three attempts.

GET
Step 2 — Retrieve Account
${baseUrl}/v1/accounts/${accountId}

Goal

Verify the integration can retrieve account information.

Procedure

typescript
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();
}

Validation

typescript
{
  accountId: string,
  name: string
}

Expected Result

HTTP 200; account returned; account identifier matches request; response successfully parsed. The workflow requires account resolution before subsequent operations.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
403Insufficient permissionsSurface access denied. Do not retry.
404Account not foundSurface account not found. Do not retry.

GET
Step 3 — Retrieve Hierarchy
${baseUrl}/v1/accounts/${accountId}/summary

Goal

Verify the integration can retrieve child accounts and linked wallets.

Procedure

typescript
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();
}

Validation

typescript
[
  {
    id: string,
    name: string,
    type: "Account" | "Wallet"
  }
]

The summary endpoint returns a combined hierarchy view of child accounts and linked wallets.

Expected Result

HTTP 200; hierarchy returned; child entities visible; wallets visible; no parsing errors.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
403Insufficient permissionsSurface access denied. Do not retry.
500, 503Service failureDisplay account detail without hierarchy and offer retry.

GET
Step 4 — Query Activities
${baseUrl}/v1/accounts/${accountId}/activities

Goal

Verify the integration can retrieve activities.

Procedure

typescript
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();
}

Validation

typescript
{
  items: [],
  metadata: {
    asOfDate: string
  }
}

The activities workflow retrieves paginated activity data and includes metadata such as asOfDate.

Expected Result

HTTP 200; activities returned; metadata returned; data successfully parsed.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid filter or query parameterCorrect the filter values. Do not retry as-is.
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
500, 503Activity service failureAccount data remains available; fail activity retrieval gracefully with a clear error message.

GET
Step 5 — Query Balances
${baseUrl}/v1/conversion/accounts/${accountId}/balances

Goal

Verify the integration can retrieve security-level account balances, interpret the balance payload, reconcile aggregate totals against holder allocations, and process the response metadata.

Procedure

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.

typescript
async 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);

Validation

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.

typescript
{
  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.

typescript
for (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.

Expected Result

HTTP 200; balance data retrieved; payload interpreted; aggregate totals reconcile with holder allocations; balance snapshot date available.

Common Error Types

This endpoint returns three distinct error envelope shapes depending on which layer rejects the request.

HTTPConditionResponse bodyExpected integration behavior
400Malformed authentication requesterrorCode, message, requestId, tracingUrlCorrect the request encoding and verify all required fields are present. Do not retry as-is.
401Invalid client credentialserrorCode, message, requestId, tracingUrlAuthentication rejected. Verify credentials before retrying.
401Expired or missing access token; GATEWAY__UNAUTHENTICATEDErrorCode, ErrorMessageRe-authenticate, then retry once.
403Requested scope not permitted for this clienterrorCode, message, requestId, tracingUrlConfirm the scope string matches what was granted at registration. Do not retry.
403Token does not grant access to this account; GATEWAY__ACCESSDENIEDErrorCode, ErrorMessageSurface access denied. Do not retry.
403User locked out; AUTHORIZATION_ENGINE__USER_LOCKED_OUT_EXCEPTIONErrorCode, ErrorMessageSurface the lockout. Do not retry until the lockout is cleared.
404Account identifier does not exist or is not accessibleerrorCode, message, requestId, tracingUrlValidate the account identifier before calling. Do not retry without correcting it.
500, 503Service failureerrorCode, errorMessageRetry with exponential backoff and a bounded retry count. Surface the failure once retries are exhausted and terminate the workflow safely.

Token Lifecycle and Resilience

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.


E2E
Step 6 — End-to-End Workflow Execution
authenticate → getAccount → getHierarchy → getActivities → getBalances

Goal

Execute the complete workflow in a single transaction.

Procedure

typescript
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 };
}

Expected Result

log
Authenticate          PASS
Retrieve Account      PASS
Retrieve Hierarchy    PASS
Query Activity        PASS
Query Balances        PASS
Workflow Complete     PASS

Each constituent call returns its expected success code.

Negative Test Cases

IDScenarioHTTPExpected result
NT-1Invalid Credentials400Authentication rejected with invalid_client. Invalid client credentials are an expected authentication failure scenario.
NT-2Expired Credential401Re-authentication required.
NT-3Invalid Account404Account Not Found.
NT-4Access Denied403Access Denied for insufficient permissions.
NT-5Activity Service Failure500, 503Account data remains available, activity retrieval fails gracefully, and the user receives a clear error message.
NT-6Invalid Client Credentials (Step 5)401Authentication rejected. Verify credentials before retrying.
NT-7Invalid Scope (Step 5)403Access denied. Confirm the scope string matches what was granted at registration.
NT-8Expired Balance Token (Step 5)401Re-authentication required; GATEWAY__UNAUTHENTICATED.
NT-9Unauthorized Account Access (Step 5)403Access denied; GATEWAY__ACCESSDENIED.
NT-10Locked Out User (Step 5)403Lockout detected; AUTHORIZATION_ENGINE__USER_LOCKED_OUT_EXCEPTION.
NT-11Malformed Authentication Request (Step 5)400Bad request. Correct the request encoding and confirm all required fields are present.
NT-12Balance Service Failure (Step 5)500, 503Retry logic executed, failure reported, and the workflow terminated safely.

Production Certification Criteria

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.

Category 2
Wallet Management

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.

Wallet registration: Wallet registration is performed through the UI and is not available through the API.
Authentication pattern: These workflows use the Service Account Credentials grant. The token request is sent to /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}.

Workflow Summary

A condensed view of the API call sequence, dependencies, and branch rules.

Authenticate

POST /connect/token
Obtain service-account token.

Load wallets

GET /v1/conversion/wallets
Display current wallet inventory.

Load reference data

GET /v1/tracking/networks
GET /v1/conversion/clients
Load in parallel.

Track status

Use wallet inventory views to monitor wallet state and status changes.

Service AccountWallet InventoryReference DataStatus Tracking
GET
List Registered Wallets
/v1/conversion/wallets

Loads existing wallets for inventory display and status review.

Request Parameters

ParameterLocationTypeRequiredDescription
CountqueryintegerOptionalPage size
OffsetqueryintegerOptionalPagination offset
searchquerystringOptionalSearch by wallet name
networksquerystring[]OptionalFilter by network name
typequerystringOptionalinternal or client
sortBy / sortOrderquerystringOptionalSorting controls

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/conversion/wallets

DirectionParameter / FieldEnum NameValues
Input (query)orderByWalletFieldsName, Network, CreatedAt
Input (query)sortOrderSortOrderAscending, Descending
Output (response)typeWalletTypesInternal, Client
Output (response)stateProcessingStatesIdle, Registering, FailedCompliance, Failed

Sample Request

typescript
const walletsResponse = await fetch(`${baseUrl}/v1/conversion/wallets`, {
  headers: { 'Authorization': `Bearer ${access_token}` }
});
const wallets = await walletsResponse.json();

Response Template

json
[
  { "id": "wallet-1", "name": "Example Wallet", "type": "CLIENT", "network": "Ethereum", "walletAddress": "0x...", "state": "Idle" }
]

TypeScript Interface

typescript
interface WalletSummary {
  id: string;
  name: string;
  type: string;
  network: string;
  walletAddress: string;
  account: AccountDetails;
  state: string;
  participant?: Participant;
}

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Terminate the inventory view safely if the failure persists.

Retry Guidance

Read-only GET; safe to retry on 5xx or network timeout.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Load Ledger and Account Reference Data
/v1/tracking/networks · /v1/conversion/clients

Fetches available ledger networks from the DTCC APIs and existing accounts from the DTCC APIs in parallel.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/tracking/networks

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending
Output (response)networkStatusNetworkStatusActive, Inactive, NA

GET /v1/conversion/clients

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending

Sample Request

typescript
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'
);

Response Template

json · /v1/tracking/networks
[
  {
    "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" }
]

TypeScript Interface

typescript
interface NetworkApiModel {
  name: string;
  displayName: string;
  networkStatus: string;
  nodeFormats: string[];
  listenerEnabled: boolean;
}
interface AccountDetails { name: string; externalId: string; id?: string; entityId?: string; }

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Keep wallet inventory available and present a meaningful error rather than terminating the workflow.

Retry Guidance

Reference data GETs are read-only and safe to retry. Both calls run in parallel and must resolve before inventory review begins.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}
Cross-service dependency: the DTCC APIs provides wallet and account reference data; the DTCC APIs provides ledger/network configuration used by wallet administration views.
Certification

Wallet Management Workflow Certification Test

CERT
Wallet Management Workflow Certification Test
Certification · v1 · Authenticate → Load Wallets → Load Ledgers + Clients → Review → Track Status

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.

Certification Workflow

Authenticate once, load wallet inventory, then retrieve ledger and client reference data in parallel before reviewing inventory and tracking status.

Authenticate

Obtain a JWT access credential using SA-WalletReader.

Load Wallet Inventory

GET /v1/conversion/wallets

Load Reference Data

/v1/tracking/networks + /v1/conversion/clients in parallel.

Review Inventory

Correlate wallets with client and account data.

Track Status

Extract and review wallet status values.

Parallel step: Ledger retrieval and client retrieval run concurrently after wallet inventory loads. Both must resolve before inventory review begins.
AuthenticationWallet InventoryReference DataStatus Tracking

Prerequisites

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.

Test Data

typescript
const tenantId = "<tenant-id>";
const baseUrl = "<base-url>";
const username = "SA-WalletReader";
const password = process.env.SERVICE_ACCOUNT_PASSWORD!;

Shared Helper Functions

typescript
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();
}

POST
Step 1 — Authentication
${baseUrl}/connect/token

Goal

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.

Procedure

typescript
const accessToken = await authenticate();

Expected Result

HTTP 200; JWT access credential returned; credential accepted by downstream APIs. Evidence: authentication successful, credential received.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid credentials; invalid clientSurface authentication rejected. Do not retry with the same credentials.
500, 503Identity Server failureRetry with exponential backoff, maximum three attempts.

GET
Step 2 — Load Wallet Inventory
${baseUrl}/v1/conversion/wallets

Goal

Verify wallet inventory can be retrieved.

Procedure

typescript
const wallets = await getWallets(accessToken);

Validation

Wallet data returned; response is non-empty; wallet identifiers present.

Expected Result

HTTP 200; wallet inventory successfully loaded. Evidence: wallet inventory response, wallet count.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid query parameters such as an invalid sort field or malformed filterCorrect the request. Do not retry as-is.
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
403Missing permissionSurface access denied. Do not retry.
500, 503Wallet endpoint failureInventory unavailable; surface the failure and terminate the workflow safely.

GET
Step 3 — Load Reference Data
${baseUrl}/v1/tracking/networks · ${baseUrl}/v1/conversion/clients

Goal

Verify ledger and client reference data can be loaded in parallel.

Procedure

typescript
const [ledgers, clients] = await Promise.all([
  getLedgers(accessToken),
  getClients(accessToken)
]);

Validation

Available ledgers returned; available client records returned.

Expected Result

HTTP 200 on both calls; reference data available and usable; parallel execution succeeds. Evidence: ledger response, client response.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
403Missing permissionSurface access denied. Do not retry.
500, 503Reference data failureDetect the failure, present a meaningful error, and keep the workflow running with wallet inventory still available.

GET
Step 4 — Review Wallet Inventory
correlate wallets with client and account data

Goal

Verify wallet inventory can be correlated with reference data.

Procedure

typescript
const inventoryView = wallets.map(wallet => ({
  wallet,
  client: clients.find(c => c.id === wallet.clientId)
}));

Validation

Wallets visible; wallets associated with client and account data; inventory records complete.

Expected Result

Inventory review completed. Evidence: sample wallet records, reference-data mapping.

Common Error Types

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.


GET
Step 5 — Track Wallet Status
extract wallet status values

Goal

Verify wallet status data is visible and reviewable.

Procedure

typescript
const walletStatuses = wallets.map(wallet => ({
  walletId: wallet.id,
  status: wallet.status
}));

Validation

Status field available; status values populated; statuses can be reported.

Expected Result

Wallet state visible; wallet status review completed. Evidence: status report, sample wallet statuses.

Common Error Types

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.


E2E
Step 6 — End-to-End Workflow Execution
executeWalletWorkflow()

Goal

Execute the complete wallet management workflow in a single run to confirm every stage succeeds in sequence.

Procedure

typescript
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 };
}

Expected Result

log
Authenticate      PASS
Load Wallets      PASS
Load Ledgers      PASS
Load Clients      PASS
Review Inventory  PASS
Track Status      PASS
Workflow Complete PASS

Each constituent call returns its expected success code.

Negative Test Cases

IDScenarioHTTPExpected result
NT-1Invalid Credentials400Authentication rejected; invalid client.
NT-2Expired Credential401Re-authentication required.
NT-3Missing Permission403Access denied.
NT-4Invalid Query Parameters400Validation error, for example an invalid sort field or malformed filter.
NT-5Reference Data Failure500, 503Failure detected; meaningful error presented; workflow does not crash.
NT-6Wallet Endpoint Failure500, 503Inventory unavailable; failure surfaced; workflow terminated safely.

Production Certification Criteria

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.

Category 3
Conversion Orders

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.

Authentication pattern: Conversion Order workflows use the OAuth 2.0 Client Credentials grant. The token request is sent to /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.

Workflow Summary

A condensed view of the API call sequence, dependencies, and branch rules.

Authenticate

POST /connect/token
Obtain service-account token.

Load securities and filters

GET /v1/conversion/securities
GET /v1/conversion/securities/issue-types
GET /v1/conversion/securities/issue-subtypes
GET /v1/tracking/networks in parallel.

Load order inputs

GET /v1/conversion/securities?status=Active
GET /v1/conversion/wallets in parallel.

Filter eligibility

Use Active securities and wallets that are Idle and conversion eligible.

Submit order

POST /v1/conversion/orders
Returns 202 Accepted with no body. Retain the idempotency key.

Poll async operation

POST /v1/conversion/async-operations/query
Poll with the idempotency key until resourceId is populated.

Retrieve order detail

GET /v1/conversion/orders/{orderId}
Use resourceId as the order identifier.

Track lifecycle

Orders are processed straight through from Processing to Completed. Failed is terminal.

Order rule: Submission requires an idempotency key, an Active security, wallets that are Idle and conversion eligible, valid conversion direction, quantity greater than zero, and server-side operational-hours compliance. Because submission returns no body, the idempotency key is the only handle on the order until the async operation exposes resourceId.
Service AccountParallel LoadingEligibilityIdempotencyAsync Polling
GET
List Registered Securities and Filter Data
/v1/conversion/securities · /v1/conversion/securities/issue-types · /v1/conversion/securities/issue-subtypes · /v1/tracking/networks

Fetches a paginated securities list alongside issue type, issue sub-type, and ledger network reference data.

Request Parameters

ParameterLocationTypeRequiredDescription
Offset / CountqueryintegerOptionalControls which slice of the securities list is returned, where offset sets the starting position and limit sets the number of records per page.
searchquerystringOptionalFree-text term matched against issuer name, security name, or CUSIP to narrow the securities list.
networkquerystringOptionalRestricts results to securities tokenized on a single ledger network, using a network name returned by the ledgers endpoint.
issueTypeIdquerystringOptionalRestricts results to a high-level security classification such as equity or debt, referenced by an identifier from the issue types endpoint.
issueSubTypeIdquerystringOptionalRestricts 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 / sortOrderquerystringOptionalDetermines which field the securities list is ordered on and whether that order runs ascending or descending.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/conversion/securities

DirectionParameter / FieldEnum NameValues
Input (query)orderByFinancialSecurityFieldsCUSIP, Description, Issuer
Input (query)sortOrderSortOrderAscending, Descending
Output (response)statusFinancialSecurityStatusOnboarding, Active, Pause, Failed
Output (response)processingStateProcessingStatesIdle, Registering, FailedCompliance, Failed

GET /v1/conversion/securities/issue-types

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending

GET /v1/conversion/securities/issue-subtypes

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending

GET /v1/tracking/networks

DirectionParameter / FieldEnum NameValues
Input (query)sortOrderSortOrderAscending, Descending
Output (response)networkStatusNetworkStatusActive, Inactive, NA

Sample Request

typescript
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();

Response Template

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" } }] }
]

TypeScript Interface

typescript
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; }

Business Rules

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.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Disable only the affected filter rather than the whole view.

Retry Guidance

All four endpoints are read-only GETs and safe to retry on 5xx or network timeout.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Load Active Securities and Registered Wallets
/v1/conversion/securities · /v1/conversion/wallets

Loads order-entry inputs in parallel and filters wallets to Idle state.

Request Parameters

ParameterLocationTypeRequiredDescription
statusquerystringYesActive
Offset / CountqueryintegerOptionalPagination controls
participantIdquerystringOptionalThe 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.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/conversion/securities

DirectionParameter / FieldEnum NameValues
Input (query)orderByFinancialSecurityFieldsCUSIP, Description, Issuer
Input (query)sortOrderSortOrderAscending, Descending
Output (response)statusFinancialSecurityStatusOnboarding, Active, Pause, Failed
Output (response)processingStateProcessingStatesIdle, Registering, FailedCompliance, Failed

GET /v1/conversion/wallets

DirectionParameter / FieldEnum NameValues
Input (query)orderByWalletFieldsName, Network, CreatedAt
Input (query)sortOrderSortOrderAscending, Descending
Output (response)typeWalletTypesInternal, Client
Output (response)stateProcessingStatesIdle, Registering, FailedCompliance, Failed

Sample Request

typescript
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');

Response Template

json
{
  "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" }
  ]
}

TypeScript Interface

typescript
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;
}

Eligibility Rules

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.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid query parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Block order submission until inputs load successfully.

Retry Guidance

Both calls are read-only GETs and safe to retry on 5xx or network timeout.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

POST
Submit and Track Conversion Orders
/v1/conversion/orders · /v1/conversion/async-operations/query · /v1/conversion/orders/{orderId}

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.

Request Parameters

GET /v1/conversion/orders

ParameterLocationTypeRequiredDescription
searchForquerystringOptionalFree-text search key filter
fromWalletquerystringOptionalSource wallet identifier filter
toWalletquerystringOptionalDestination wallet identifier filter
updateFrom / updateToquerystringOptionalLower and upper bounds of the update date range
idsqueryarrayOptionalFilter by specific order identifiers
financialSecurityIdsqueryarrayOptionalFilter by security identifiers
statusqueryarrayOptionalFilter by order status
originqueryarrayOptionalFilter by how the order was originated
includeObacquerybooleanOptionalInclude access control metadata when true
orderBy / sortOrderquerystringOptionalSorting controls
Offset / CountqueryintegerOptionalPagination controls

POST /v1/conversion/orders

ParameterLocationTypeRequiredDescription
X-Idempotency-KeyheaderstringYesMax 255 characters; prevents duplicate submissions. Retain this value for the async operation query.
financialSecurityIdbodystring UUIDYesSecurity being converted
fromWalletIdbodystring UUIDYesThe 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.
toWalletIdbodystring UUIDYesThe 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.
activityTypebodystringYesMemoSeg 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.
quantitybodystringYesAmount to convert; must be greater than zero
participantIdbodystringOptionalThe 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.
notebodystringOptionalOptional order note

POST /v1/conversion/async-operations/query

ParameterLocationTypeRequiredDescription
idempotencyKeysbodyarrayYesOne or more idempotency keys retained from prior submissions
Offset / CountbodyintegerOptionalPagination controls

GET /v1/conversion/orders/{orderId}

ParameterLocationTypeRequiredDescription
orderIdpathstring UUIDYesOrder identifier, taken from resourceId on the async operation response

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/conversion/orders

DirectionParameter / FieldEnum NameValues
Input (query)orderByOrderFieldsCreatedAt, UpdatedAt
Input (query)sortOrderSortOrderAscending, Descending
Input (query)statusOrderStatusProcessing, Completed, Failed
Input (query)originOrderOriginParticipant, Admin, ForcedReconversion
Output (response)statusOrderStatusProcessing, Completed, Failed
Output (response)originOrderOriginParticipant, Admin, ForcedReconversion

POST /v1/conversion/async-operations/query

DirectionParameter / FieldEnum NameValues
Output (response)objectKindObjectKindUndefined, Order, Wallet, FinancialSecurity
Output (response)statusAsyncOperationStatusNew, Processing, Completed, Failed
Output (response)operationNameOperationNameUndefined, Register, Submit, Import

GET /v1/conversion/orders/{orderId}

DirectionParameter / FieldEnum NameValues
Output (response)statusOrderStatusProcessing, Completed, Failed
Output (response)originOrderOriginParticipant, 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.

Sample Request

GET /v1/conversion/orders

typescript
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

typescript
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

typescript
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}

typescript
const detailResponse = await fetch(`${baseUrl}/v1/conversion/orders/${orderId}`, {
  headers: { 'Authorization': `Bearer ${access_token}` }
});
const orderDetail: OrderDetailResponse = await detailResponse.json();
// orderDetail.status === 'Processing'

Response Template

GET /v1/conversion/orders

json
[
  {
    "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

json
[
  {
    "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}

json
{
  "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"
}

TypeScript Interface

typescript
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;
}

Business Rules

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.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request, missing X-Idempotency-Key, or quantity of zeroCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Security, wallet, or order identifier not foundSurface not found. Do not create a replacement order.
409Duplicate X-Idempotency-KeyTreat the order as already submitted. Query the async operation with the same key to resolve the existing order identifier.
422Business rule violation such as invalid conversion direction, ineligible security, ineligible wallet, or submission outside operational hoursSurface the specific rule violation. Do not retry until the input is corrected.
500, 503Service failureRetry with the same X-Idempotency-Key, maximum three attempts.

Retry Guidance

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.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}
Operational WindowMonday to Friday, 02:00 to 18:15 ET
Business RuleConversion direction must be DTC_Classic to non-Classic or vice versa
Cross-service dependency: the DTCC APIs provides securities, wallets, and order management. the DTCC APIs provides ledger/network reference data for filtering.
Certification

Conversion Order Certification Tests

CERT
Conversion Order Certification Tests
Certification · v2 · Auth → Reference Data → Eligibility → Submit → Async → Retrieve → Lifecycle → Audit

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.

Certification Workflow

Authenticate, load reference data in parallel, validate eligibility, submit, then track the order asynchronously to a terminal state.

Authenticate

OAuth 2.0 Client Credentials against /connect/token.

Load Reference Data

Orders, securities, and wallets in parallel, plus issue type, issue sub-type, and ledger filters.

Validate Security

Security status equals Active.

Validate Wallet

Wallet state equals Idle and conversionEligible is true.

Submit Order

POST /v1/conversion/orders returns 202 Accepted with no body.

Track Async Operation

Query by X-Idempotency-Key until a terminal status.

Correlate To Order

resourceId resolves the order identifier.

Retrieve Order Detail

GET /v1/conversion/orders/{orderId}.

Validate Lifecycle And Audit

Processing to Completed, then reconstruct the audit trail.

Order submission rule: Submission does not execute the conversion and returns no response body. Completion must be determined through async operation tracking rather than assumed from the submission response. Enforcement of operational hours, idempotency, direction, and eligibility occurs server side at submission time.
Client CredentialsParallel LoadingEligibilityIdempotencyAsync TrackingAudit

Key Business Rules

RuleRequirement
Security EligibilityKnown security states are Onboarding, Active, Pause, and Failed. Only Active securities are eligible for conversion-order creation.
Wallet EligibilityKnown wallet states are Idle, Registering, FailedCompliance, and Failed. Only wallets that are Idle and conversion eligible may be used.
Conversion DirectionConversion must occur between DTC Classic and digital wallets.
Quantity ValidationQuantity must be greater than zero.
IdempotencyEvery submission must include X-Idempotency-Key. The same key must remain traceable throughout asynchronous processing.
Asynchronous ProcessingOrder creation returns HTTP 202 Accepted. Completion is determined through async operation tracking, not from the submission response.
Operational HoursMonday to Friday, 02:00 ET to 18:15 ET. Enforcement is server-side.

Test Data

typescript
const baseUrl = "<base-url>";
const clientId = process.env.CLIENT_ID!;
const clientSecret = process.env.CLIENT_SECRET!;
const scope = process.env.CONVERSION_SCOPE!;

Shared Helper Functions

typescript
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();
}

POST
Step 1 — Authentication
${baseUrl}/connect/token

Goal

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.

Procedure

typescript
const token = await authenticate();
const accessToken = token.access_token;

Validation

The response returns access_token, token_type, expires_in, and scope. The credential is usable on a subsequent API call.

Expected Result

HTTP 200; credential issued and usable.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid client credentials or malformed grant requestCorrect the credentials. Do not retry with the same values.
403Requested scope not granted to the clientSurface the scope failure. Do not retry.
500, 503Identity service failureRetry with exponential backoff, maximum three attempts.

GET
Step 2 — Reference Data Retrieval
loadReferenceData() · loadFilterData()

Goal

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.

Procedure

typescript
const { orders, securities, wallets } = await loadReferenceData(accessToken);
const { issueTypes, issueSubTypes, ledgers } = await loadFilterData(accessToken);

Validation

Order inventory returned. Security inventory returned. Wallet inventory returned. Issue type reference data returned. Issue sub-type reference data returned. Ledger network data returned.

Expected Result

HTTP 200 on each call; all six data sets available for downstream steps.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid access credentialRe-authenticate, then retry once.
403Client lacks the required permission scopeSurface access denied. Do not retry.
500, 503Service failureRetry with exponential backoff. Each call fails independently, so present a partial state rather than blocking the whole load.

GET
Step 3 — Security Validation
status equals Active

Goal

Verify that a valid conversion security can be identified from the security inventory loaded in Step 2.

Procedure

typescript
const security = securities.find(security => security.status === "Active");

Validation

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.

Expected Result

Eligible security identified.

Common Error Types

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.


GET
Step 4 — Wallet Validation
state equals Idle and conversionEligible is true

Goal

Verify that suitable source and destination wallets can be selected from the wallet inventory loaded in Step 2.

Procedure

typescript
const eligibleWallets = wallets.filter(
  wallet => wallet.state === "Idle" && wallet.conversionEligible === true
);

Validation

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.

Expected Result

Eligible wallets identified.

Common Error Types

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.


POST
Step 5 — Order Submission
${baseUrl}/v1/conversion/orders

Goal

Verify that a conversion order can be submitted with a valid idempotency key and accepted for asynchronous processing.

Procedure

typescript
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"
  })
});

Validation

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.

Expected Result

HTTP 202 Accepted with no response body.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request, missing X-Idempotency-Key, or quantity of zeroCorrect the request. Do not retry as-is.
403Client lacks the required permission, or the account is lockedSurface access denied. Do not retry.
409Duplicate X-Idempotency-KeyTreat the order as already submitted. Query the async operation with the same key to resolve the existing order.
422Business rule violation such as invalid direction, ineligible security, ineligible wallet, or submission outside operational hoursSurface the specific rule violation. Do not retry until the input is corrected.
500, 503Service failureRetry with the same X-Idempotency-Key, maximum three attempts.

POST
Step 6 — Idempotency Validation
duplicate submission with same X-Idempotency-Key

Goal

Verify that resubmitting an identical request with the same idempotency key does not create a duplicate order.

Procedure

Submit the same order request twice using the same X-Idempotency-Key.

Validation

A duplicate order is not created, idempotency is maintained, and the operation remains traceable under the original key.

Expected Result

Duplicate processing prevented.

Common Error Types

HTTPConditionExpected integration behavior
409Duplicate X-Idempotency-KeyTreat as already submitted. Reconcile against the existing order rather than resubmitting.
400X-Idempotency-Key omitted entirelySubmission rejected. Add the header before retrying.

POST
Step 7 — Async Operation Validation
${baseUrl}/v1/conversion/async-operations/query

Goal

Verify that asynchronous operations can be monitored using the idempotency key retained at submission.

Procedure

typescript
const operation = await queryOperation(accessToken, idempotencyKey);

Validation

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.

Expected Result

HTTP 200; async operation successfully tracked.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid access credentialRe-authenticate, then retry once.
500, 503Service failureRetry with exponential backoff. The query is read-only and safe to repeat.

GET
Step 8 — Async-to-Order Correlation
resourceId resolves the order identifier

Goal

Verify that an async operation can be correlated to the order it produced.

Procedure

typescript
const operation = await queryOperation(accessToken, idempotencyKey);
const order = await getOrder(accessToken, operation.resourceId);

Validation

resourceId is populated, resourceUrl is populated, the referenced order exists, and the order is retrievable.

Expected Result

HTTP 200; async operation successfully correlated to an order.

Common Error Types

HTTPConditionExpected integration behavior
404resourceId references an order that cannot be retrievedSurface not found. Do not create a replacement order.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

GET
Step 9 — Retrieve Final Order
${baseUrl}/v1/conversion/orders/{orderId}

Goal

Verify that final order detail can be accessed once the order identifier is known.

Procedure

typescript
const orderDetail = await getOrder(accessToken, operation.resourceId);

Validation

The response carries order identifier, status, participant information, transaction information, and audit timestamps.

Expected Result

HTTP 200; order detail successfully retrieved.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid access credentialRe-authenticate, then retry once.
404Order identifier not foundSurface not found. Do not create a replacement order.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

GET
Step 10 — Lifecycle Validation
order status transitions

Goal

Verify that lifecycle transitions can be monitored through to a terminal state.

Validation

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.

Expected Result

HTTP 200; current order status returned and reportable.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid access credentialRe-authenticate, then retry once.
404Order identifier not foundSurface not found. Do not create a replacement order.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

GET
Step 11 — Audit Validation
end-to-end transaction trace

Goal

Verify that the complete transaction history can be reconstructed from the artifacts produced across the workflow.

Validation

The order identifier is traceable, the idempotency key is traceable, the async operation is traceable, audit timestamps are available, and transaction identifiers are available.

Expected Result

End-to-end audit trace established.

Common Error Types

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.


E2E
Step 12 — End-to-End Workflow Execution
complete conversion order lifecycle

Goal

Execute the complete workflow from authentication through audit validation in a single uninterrupted run.

Validation

text
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               PASS

Each constituent call returns its expected success code.

Expected Result

Complete workflow executed and every stage verified.

Negative Test Cases

IDScenarioHTTPExpected result
NT-1Invalid client credentials400Authentication rejected.
NT-2Invalid security422Order rejected.
NT-3Ineligible wallet422Order rejected.
NT-4Missing idempotency key400Request rejected.
NT-5Expired access credential401Authorization failure; re-authentication required.
NT-6Async processing failureAsync operation returns Failed status with errorCode and errorMessage present. Not an HTTP error condition.
NT-7Invalid order retrieval404Order not found; error handled without creating a replacement order.
NT-8Service unavailable503Retry attempted, failure reported, workflow stops safely.

Production Certification Criteria

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.

Category 4
Corporate Actions

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.

Authentication pattern: These workflows use the Service Account Credentials grant. The token request is sent to /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}.

Workflow Summary

A condensed view of the API call sequence, dependencies, and branch rules.

Authenticate

POST /connect/token
Obtain service-account token.

Load events

GET /v1/corporate-actions
Retrieve paginated events.

Load filter data

GET /v2/corporate-actions/event-types
GET /v1/conversion/securities
Load in parallel.

Inspect event

GET /v2/corporate-actions/{id}
Retrieve full event detail.

Apply context

Interpret status, category, DTC mandatory classification, support flag, and relevant core dates.

Detail rule: Full corporate action detail is returned from GET /v2/corporate-actions/{id}, including security data, event classification, core dates, DTC mandatory classification, support status, and payout-related metadata.
Service AccountParallel LoadingEvent FiltersEvent Detail
GET
List Corporate Action Events and Reference Data
/v1/corporate-actions · /v2/corporate-actions/event-types · /v1/conversion/securities

Fetches the events list alongside event taxonomy and securities filter options.

Request Parameters

ParameterLocationTypeRequiredDescription
searchForquerystringOptionalFree-text term matched against event and security fields to narrow the result set.
orderByqueryEventFields enumOptionalField the results are sorted on, such as last-updated timestamp, payable date, or business event number.
sortOrderquerySortOrder enumOptionalDirection applied to the chosen sort field, either ascending or descending.
ids / eventIdsquerystring[]OptionalLimits results to specific records, referenced either by the platform's internal record key or by the business-facing event number; up to 50 values.
eventTypesqueryEventTypeEnumeration[]OptionalLimits results to one or more high-level corporate action classifications, such as a cash dividend or a reorganization; up to 50 values.
subEventTypesqueryint32[]OptionalLimits results to the finer classifications nested beneath a high-level type, such as a deemed dividend; up to 50 values.
eventSecurityIdsquerystring[]OptionalLimits results to events affecting particular securities, referenced by their platform identifier; up to 50 values.
statusqueryEventStatusEnumeration[]OptionalLimits results to events sitting in particular approval or cancellation states; up to 5 values.
offset / countqueryint32OptionalControls which slice of the result set is returned, where offset is the starting position and count is the number of records per page.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v1/corporate-actions

DirectionParameter / FieldEnum NameValues
Input (query)eventTypeEventTypeEnumerationAutomaticDividendReinvestment, 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)statusEventStatusEnumerationApproved, ConditionallyApproved, Incomplete, Cancelled, Deleted
Input (query)sortOrderSortOrderAscending, Descending
Input (query)orderByEventFieldsId, EventId, EventType, SubEventType, Status, Security, SecurityId, PositionCaptureDate, PayableDate, AnticipatedPayDate, InstructionExpirationDate, CreatedAt, UpdatedAt
Output (response)eventTypeEventTypeEnumerationSame values as listed above.
Output (response)subEventTypeSubEventTypeEnumerationNone, 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)statusEventStatusEnumerationApproved, ConditionallyApproved, Incomplete, Cancelled, Deleted
Output (response)dtcMandatoryDtcMandatoryMandatory, MandatoryWithOptions, Voluntary
Output (response)eventCategoryEventCategoryInterestOnTreasury, MaturityOnTreasury, MandatoryCashDistribution, MandatorySecurityDistribution, MandatoryWithChoiceDistribution, MandatoryReorganization, VoluntaryReorganization, Meetings

GET /v2/corporate-actions/event-types

DirectionParameter / FieldEnum NameValues
Output (response)eventTypeEventTypeEnumerationSame values as listed for GET /v1/corporate-actions above.
Output (response)subEventTypeSubEventTypeEnumerationSame values as listed for GET /v1/corporate-actions above.

GET /v1/conversion/securities

DirectionParameter / FieldEnum NameValues
Input (query)orderByFinancialSecurityFieldsCUSIP, Description, Issuer
Input (query)sortOrderSortOrderAscending, Descending
Output (response)statusFinancialSecurityStatusOnboarding, Active, Pause, Failed
Output (response)processingStateProcessingStatesIdle, Registering, FailedCompliance, Failed

Sample Request

typescript
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();

Response Template

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" } }
]

TypeScript Interface

typescript
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;
}

Status Values

Approved, ConditionallyApproved, Incomplete, Cancelled, and Deleted.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Malformed request or invalid filter parameterCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Resource not foundSurface not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts. Keep the workflow stable and disable only the affected filter.

Retry Guidance

All three calls are read-only GETs and safe to retry on 5xx or network timeout.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

GET
Get Corporate Action Event Detail
/v2/corporate-actions/{id}

Retrieves full detail for a specific corporate action event.

Request Parameters

ParameterLocationTypeRequiredDescription
idpathstringYesUnique key of a single corporate action event, taken from the results of the event list call.

Enumerations

Enumeration values must be provided exactly as they are defined; they are case-sensitive.

GET /v2/corporate-actions/{id}

DirectionParameter / FieldEnum NameValues
Output (response)eventTypeEventTypeEnumerationAutomaticDividendReinvestment, 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)subEventTypeSubEventTypeEnumerationNone, 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)statusEventStatusEnumerationApproved, ConditionallyApproved, Incomplete, Cancelled, Deleted
Output (response)dtcMandatoryDtcMandatoryMandatory, MandatoryWithOptions, Voluntary
Output (response)eventCategoryEventCategoryInterestOnTreasury, MaturityOnTreasury, MandatoryCashDistribution, MandatorySecurityDistribution, MandatoryWithChoiceDistribution, MandatoryReorganization, VoluntaryReorganization, Meetings
Output (response)positionProcessingStatusPositionProcessingStatusNew, Processed, Failed

Sample Request

typescript
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();

Response Template

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 }
}

TypeScript Interface

typescript
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>;
}

Single Endpoint Detail

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.

Error Handling

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.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid event identifier formatCorrect the request. Do not retry as-is.
401JWT access credential missing, expired, or invalidRequest a new JWT access credential, then retry once.
403Service account lacks the required permission, or the account is lockedSurface access denied. Do not retry.
404Invalid or deleted eventSurface event not found. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

Retry Guidance

Read-only GET; safe to retry on 5xx or network timeout. Use exponential backoff with a maximum of three retries.

Permissions & Scopes

Auth PatternService Account Credentials grant
Credential DeliveryAuthorization: Bearer {access_token}

Core Dates by Event Category

CategoryRelevant Core Dates
InterestOnTreasurydeclaredPayableDate, allocationDateTime
MaturityOnTreasurydeclaredPayableDate, allocationDateTime
MandatoryCashDistributionexDate, recordDate, dtcPositionCaptureDate or captureDate, declaredPayableDate, anticipateDate, allocationDateTime
MandatorySecurityDistributionexDate, recordDate, positionCaptureDate, allocationDateTime
MandatoryWithChoiceDistributionexDate, recordDate, positionCaptureDate, instructionExpiration, allocationDateTime
MandatoryReorganizationeffectiveDateCompany, positionCaptureDate, allocationDateTime, reconversionDate
VoluntaryReorganizationdtcInstructionExpirationDateTime, positionCaptureDate, allocationDateTime
MeetingsmeetingDate

DTC Mandatory Classification

ValueMeaning
MandatoryParticipation is automatic; no election required.
MandatoryWithOptionMandatory but participants may choose from options.
VoluntaryParticipation requires explicit election by the holder.
Retry and dependencies: Event list, event type, securities, and event-detail calls are read-only GET requests and can be retried on network or service failures. The DTCC APIs provides event listing, taxonomy, securities reference data, and event details.
Certification

Corporate Actions Workflow Certification Test

CERT
Corporate Actions Workflow Certification Test
Certification · v1 · Load Events → Load Types + Securities → Inspect → Apply Context

This certification verifies both API connectivity and the customer's ability to correctly interpret corporate action event data.

Certification Workflow

Authenticate, load events, load event types and securities in parallel, inspect the event, then apply context.

Authenticate

Obtain a JWT access credential using SA-CorporateActionsBot.

Load Events

GET /v1/corporate-actions

Load Types + Securities

event-types plus securities in parallel.

Inspect Event

GET /v2/corporate-actions/{id}

Apply Context

Status, category, DTC classification, and core dates.

Single endpoint detail: All event detail information is retrieved from GET /v2/corporate-actions/{id}. No additional entitlement endpoint is required.
AuthenticationParallel LoadingEvent FiltersEvent Detail

Key Business Rules

RuleRequirement
Parallel LoadingRetrieve events, event types, and securities concurrently.
Supported StatusesApproved, ConditionallyApproved, Incomplete, Cancelled, Deleted.
Detail RetrievalAll detail information is retrieved from GET /v2/corporate-actions/{id}.
Context InterpretationCustomers must correctly apply status, category, DTC mandatory classification, support indicator, and core dates.

Prerequisites

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}.

Test Data

typescript
const tenantId = "<tenant-id>";
const baseUrl = "<base-url>";
const username = "SA-CorporateActionsBot";
const password = process.env.SERVICE_ACCOUNT_PASSWORD!;

Shared Helper Functions

typescript
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();
}

POST
Step 1 — Authentication
${baseUrl}/connect/token

Goal

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.

Expected Result

HTTP 200; JWT access credential returned; credential accepted by downstream APIs.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid credentialsSurface authentication rejected. Do not retry with the same credentials.
500, 503Identity Server failureRetry with exponential backoff, maximum three attempts.

GET
Step 2 — Load Corporate Action Events
${baseUrl}/v1/corporate-actions

Goal

Verify the integration can retrieve a paginated corporate action event inventory with statuses and event identifiers populated.

Procedure

typescript
const data = await loadCorporateActionsData(accessToken);

Validation

Events returned; pagination supported; statuses populated; event identifiers returned.

Expected Result

HTTP 200; corporate action inventory loaded successfully.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid filter parametersCorrect the request. Do not retry as-is.
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
403Missing permissionSurface access denied. Do not retry.
500, 503Service failureRetry with exponential backoff, maximum three attempts.

GET
Step 3 — Load Event Type Taxonomy
${baseUrl}/v2/corporate-actions/event-types

Goal

Verify the integration can retrieve the event type and sub-event type taxonomy used for hierarchical event filtering.

Validation

Event types returned; sub-event types returned; hierarchy available.

Expected Result

HTTP 200; event taxonomy successfully loaded.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
500, 503Event-type service unavailableFilter data unavailable; display a meaningful error and keep the workflow stable.

GET
Step 4 — Load Securities Filter Data
${baseUrl}/v1/conversion/securities

Goal

Verify the integration can retrieve securities reference data, including CUSIPs and support flags, for filtering corporate action events.

Validation

Security identifiers returned; CUSIPs returned; support flags returned.

Expected Result

HTTP 200; security filtering possible.

Common Error Types

HTTPConditionExpected integration behavior
401Expired or invalid JWT access credentialRe-authenticate, then retry once.
500, 503Securities service unavailableSecurity filter unavailable; display a meaningful error and keep the workflow stable.

GET
Step 5 — Event Filtering
filter by status, type, sub-type, security, and search text

Goal

Verify the integration can narrow the event inventory to a relevant subset using status, event type, sub-event type, security, and search text.

Procedure

typescript
const approvedEvents = events.filter(
  event => event.status === "Approved"
);

Validation

Successful filtering by status, event type, sub-event type, security, and search text.

Expected Result

Relevant events identified.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid filter parametersValidation error. Correct the filter values before retrying.

GET
Step 6 — Retrieve Event Detail
${baseUrl}/v2/corporate-actions/{id}

Goal

Verify the integration can retrieve full event detail from the single detail endpoint, including security, category, status, classification, and core dates.

Procedure

typescript
const detail = await getEventDetail(accessToken, eventId);

Validation

Security returned; category returned; status returned; DTC classification returned; core dates returned.

Expected Result

HTTP 200; event detail successfully retrieved.

Common Error Types

HTTPConditionExpected integration behavior
400Invalid event identifier formatCorrect the request. Do not retry as-is.
404Invalid event ID; event not foundSurface event not found. Do not retry.
500, 503Event detail service failureInvoke retry logic with exponential backoff and handle the failure gracefully.

GET
Step 7 — Apply Event Context
interpret category, status, support flag, and DTC classification

Goal

Verify the integration derives correct business context from the returned category, status, support indicator, and DTC classification.

Procedure

typescript
if (detail.dtcMandatory === "Voluntary") {
  console.log("Election Required");
}

Validation

Interpret category, status, support flag, and DTC classification.

Expected Result

Business context successfully derived.

Common Error Types

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.


GET
Step 8 — Category-Specific Date Interpretation
identify relevant dates by category

Goal

Verify the integration identifies the correct set of lifecycle dates for each corporate action category it processes.

Required Dates by Category

CategoryRequired Dates
InterestOnTreasurydeclaredPayableDate, allocationDateTime
MaturityOnTreasurydeclaredPayableDate, allocationDateTime
MandatoryCashDistributionexDate, recordDate, captureDate, declaredPayableDate, anticipateDate, allocationDateTime
MeetingsmeetingDate

Validation

Correctly identify the relevant dates for at least one event available in each category.

Expected Result

The correct set of lifecycle dates is identified for each category present in the test dataset.

Common Error Types

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.


GET
Step 9 — DTC Classification Interpretation
classify events by returned values

Goal

Verify the integration correctly classifies each event as Mandatory, MandatoryWithOption, or Voluntary and acts on whether an election is required.

Classification Values

ValueMeaning
MandatoryParticipation automatic.
MandatoryWithOptionOptions available to holder.
VoluntaryElection required.

Validation

The customer correctly classifies events using the returned values.

Expected Result

Each event is classified as Mandatory, MandatoryWithOption, or Voluntary, and election requirements are applied accordingly.

Common Error Types

This step performs no API calls. An unrecognized dtcMandatory value must be surfaced as an unhandled classification rather than defaulted to Mandatory.


E2E
Step 10 — End-to-End Workflow Execution
executeWorkflow()

Goal

Execute the complete corporate actions workflow in a single run to confirm every stage succeeds in sequence.

Procedure

typescript
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 };
}

Expected Result

log
Authentication    PASS
Load Events       PASS
Load Event Types  PASS
Load Securities   PASS
Filter Events     PASS
Retrieve Detail   PASS
Apply Context     PASS
Workflow Complete PASS

Each constituent call returns its expected success code.

Negative Test Cases

IDScenarioHTTPExpected result
NT-1Invalid Credentials400Authentication rejected.
NT-2Expired Credential401Re-authentication required.
NT-3Invalid Event ID404Event not found.
NT-4Missing Permission403Access denied.
NT-5Invalid Filter Parameters400Validation error.
NT-6Event-Type Service Unavailable500, 503Filter data unavailable; meaningful error displayed; workflow remains stable.
NT-7Securities Service Unavailable500, 503Security filter unavailable; meaningful error displayed; workflow remains stable.
NT-8Event Detail Service Failure500, 503Retry logic invoked; graceful failure handling.

Production Certification Criteria

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.

Release History
Site Changelog

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.

RELEASE
Version 1.5
September 17, 2026

Wallet Management

  • Corrected the ledgers endpoint path from /v1/networks/ledgers to /v1/tracking/networks to match the API specification.
  • Updated the response template and TypeScript interface to the flat network model with name, displayName, networkStatus, nodeFormats, and listenerEnabled, and fixed the sample request filter accordingly.
  • Renamed the response enumeration field from status to networkStatus and removed the nodeStatus / NetworkNodeStatus row, which the specification does not define.

Pagination Model

  • Expanded the Endpoint Support table to list every endpoint in the endpoint catalog, added a Method column, and recorded pagination support for each based on the API specifications.
RELEASE
Version 1.4
September 16, 2026

Conversion Orders

  • Replaced the certification section with twelve steps drawn from the Conversion Order Lifecycle Workflow Certification Test v2, covering authentication, reference data retrieval, security validation, wallet validation, order submission, idempotency, async operation tracking, async-to-order correlation, final order retrieval, lifecycle validation, audit validation, and end-to-end execution. Renamed the card to Conversion Order Certification Tests.
  • Excluded Test 11 Maker-Checker Validation, and removed maker and checker references from the order detail validation model, the end-to-end checklist, and the workflow diagram so nothing points at an excluded test.
  • Removed Declined from the lifecycle states, leaving Processing, Completed, and Failed.
  • Switched the authentication pattern to the OAuth 2.0 Client Credentials grant and recorded the departure from the Service Account Credentials grant used by the other API families.
  • Added 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.
  • Kept the four-call filter loader as loadFilterData and extended Step 2 to call it, so the issue type, issue sub-type, and ledger endpoints remain within the certification.
  • Replaced the negative test cases with eight scenarios, assigning HTTP codes only where the guide already documents them and leaving the async processing failure without one because a Failed async status is not an HTTP condition.
  • Renamed the pagination parameters to Offset and Count on the orders list, the securities list, the wallets list, and the async operation query.

Account Management

  • Renamed the wallet type field to type on the account balances card.
  • Left limit and offset unchanged on the account hierarchy summary and account activities cards.

Wallet Management

  • Renamed the wallet fields to type and state, matching the API integration guide, and removed the note that recorded the earlier naming discrepancy.
  • Renamed the pagination parameters to Offset and Count.

Corporate Actions

  • Left offset and count unchanged.

All Endpoint Tabs

  • Added a case-sensitivity callout to all ten Enumerations sections stating that enumeration values must be provided exactly as defined.
  • Removed Deleting from the ProcessingStates values in all five places it appeared, covering both wallet and security rows so the enumeration keeps a single definition.
  • Renamed the idempotency header to X-Idempotency-Key throughout.
  • Replaced the remaining COE_SCOPE environment variable reference with API_SCOPE.

Authentication and Authorization

  • Added an exception recording that Conversion Order endpoints use the OAuth 2.0 Client Credentials grant rather than the Service Account Credentials grant described in the panel.

Pagination Model

  • Added a Pagination Model hero button and modal panel documenting offset-based pagination, the Offset and Count query parameters, the X-Paging response headers, endpoint support, and iteration guidance.
  • Recorded that the async operation query accepts Offset and Count in the request body rather than the query string, an exception to the model's general rule.
RELEASE
Version 1.3
September 15, 2026

Conversion Orders

  • Documented the asynchronous submission contract. 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.
  • Added three endpoints: GET /v1/conversion/orders, POST /v1/conversion/async-operations/query, and GET /v1/conversion/orders/{orderId}.
  • Renamed the Submit Conversion Order card to Submit and Track Conversion Orders, and gave each of its four endpoints its own labeled Request Parameters table and Enumerations table.
  • Removed the response enumerations from the submission endpoint, which described fields a 202 response does not return. Relocated asyncOperationStatus, objectKind, and operationName to the async operation query, and orderBy to the orders list.
  • Added the OrderOrigin enumeration with values Participant, Admin, and ForcedReconversion.
  • Extended wallet eligibility to require 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.
  • Expanded the workflow summary from six steps to eight, adding the async operation poll and the order detail retrieval.
  • Documented querying the orders list before submission to detect whether a prior submission with the same intent already exists.
  • Reduced the certification test to Step 1 Eligibility Validation and Step 2 Lifecycle Validation, renumbered from the former Steps 4 and 6. Step 2 was rewritten for the asynchronous contract, resolving resourceId before retrieving the order. Remaining certification steps are being regenerated.

Account Management

  • Added Failed to the FinancialSecurityStatus values published on the account balances card.

Wallet Management

  • Added FailedCompliance and Failed to the ProcessingStates values.
  • Recorded that the COE integration guide publishes the wallet type and processing state fields as type and state, while the guide follows the enumeration reference document naming.

Corporate Actions

  • Carried the FinancialSecurityStatus and ProcessingStates value additions into the securities reference enumerations on the events card.

Overview

  • Extended the Conversion Orders journey row with the async operation query and order detail endpoints.

API Families

  • Added the async operation query and order detail endpoints to the Conversion Orders APIs box.

Workflow Patterns

  • Added the async operation poll and order detail retrieval steps to the Conversion Orders pattern.

Endpoint Catalog

  • Added rows for the three new conversion endpoints and noted that submission returns 202 Accepted with no response body.
RELEASE
Version 1.2
September 9, 2026

Account Management

  • Rebuilt the Enumerations tables on the account hierarchy summary, account activities, and account balances cards to the four-column shape used in the enumeration reference document, with Direction as the leading column and a method and path label above each table.

Wallet Management

  • Rebuilt the registered wallets Enumerations table to the four-column shape with Direction leading.
  • Split the ledger and account reference data Enumerations table into separate labeled tables for /v1/tracking/networks and /v1/conversion/clients.

Conversion Orders

  • Split the registered securities and filter data Enumerations table into four labeled tables, one per endpoint.
  • Split the active securities and registered wallets Enumerations table into two labeled tables, one per endpoint.
  • Rebuilt the Submit Conversion Order Enumerations table to the four-column shape with Direction leading.

Corporate Actions

  • Split the events and reference data Enumerations table into three labeled tables, one per endpoint.
  • Rebuilt the event detail Enumerations table to the four-column shape with Direction leading.
RELEASE
Version 1.1
September 9, 2026

Conversion Orders

  • Removed the PendingApproval status from the conversion order lifecycle. Orders are processed straight through from Processing to Completed, with Failed retained as the terminal failure state.
  • Removed Declined from the OrderStatus enumeration along with the approval decision it recorded.
  • Removed maker-checker approval references from the category lead, the workflow summary, the order submission rule, and the Conversion Orders certification test.
  • Added a pre-submission recommendation to the Submit Conversion Order card advising retrieval and verification of the wallet and securities before an order is submitted.
  • Expanded the category lead to describe conversions between electronic book entry and digital tokenized forms, and to state that the process is identical in both directions with only the source and destination assignments differing.
  • Added Enumerations tables to the registered securities and filter data card, the active securities and registered wallets card, and the Submit Conversion Order card.

Account Management

  • Expanded the category lead to describe how accounts organize wallets, and to document the Internal and Clients accounts configured by default.
  • Added Enumerations tables to the account hierarchy summary card, the account activities card, and the account balances card.

Wallet Management

  • Added Enumerations tables to the registered wallets card and the ledger and account reference data card.

Corporate Actions

  • Added Enumerations tables to the events and reference data card and the event detail card, covering the full event type and sub-event type taxonomies, event status, DTC mandatory classification, event category, and position processing status values.

Overview

  • Replaced the maker-checker lifecycle reference in the Conversion Orders domain card with order lifecycle tracking.

API Families

  • Split the first four conversion endpoints out of the Conversion Orders APIs box into a dedicated Eligible Securities APIs box.

Workflow Patterns

  • Replaced the Maker-checker lifecycle step in the Conversion Orders workflow pattern with Track lifecycle.

Changelog

  • Added this tab to record changes applied to the guide.