Skip to main content
Whether you are an exchange, a wallet or a platform, DCS tells you over a real-time channel whenever a user’s KYC, balance, card or order changes, so you never have to poll. This page gets both channels working in one pass:
  • Webhook: push based. You expose an HTTPS callback endpoint and DCS pushes signed JSON to it as events occur. Best suited to stable server-to-server delivery.
  • WebSocket: subscription based, and a DeCard-Managed differentiator. You first obtain a dedicated private channel, then hold a wss connection open to receive messages live; if you miss anything, you can replay history by version. Best suited to cases that need front-end or gateway awareness in real time, or that require a replay path for reconciliation.
Privacy red line: the DeCard-Managed model handles a great deal of end-user personal data. Every externalUserId, card number, merchant name, address, txHash and secretKey in the examples on this page is a placeholder or masked value and must not be treated as real data. Mask the same fields in your own receiver logs, and never record real PII or keys in clear text.

1. Webhook (push based)

1.1 Core capabilities

  • Automatic retries: when delivery fails, DCS retries automatically, up to 3 times.
  • Signature verification: every notification carries an X-Signature digital signature in the request header so you can trust its origin.
  • Idempotency: every event carries a globally unique webhookId that you can deduplicate on.

1.2 Prerequisites and integration steps

Step 1: Implement the Webhook receiver

Your service must expose a POST endpoint that meets the following requirements:
  • Accepts an application/json request body;
  • Returns 200 OK to acknowledge receipt. Any other status code makes DCS retry;
  • Must respond within 2 seconds (both the connect timeout and the socket timeout on the DCS side are 2000 ms), otherwise the delivery counts as a timeout failure and is likewise retried.

Step 2: Give DCS the callback URL to configure

Send the callback URL you implemented in step 1 to the DCS team. It must be HTTPS and reachable from the public internet.

Step 3: Verify, then go live

Verify in the UAT (sandbox) environment first, and go live in production only once verification passes.

1.3 Delivery sequence and retries

Webhook delivery sequence and retriesWebhook delivery sequence and retries

1.4 Security: X-Signature verification

To keep the channel secure, DCS carries X-Signature in the headers of every Webhook request. The signature is produced with HmacSHA256: DCS computes it over the raw body using your SecretKey. On receipt, recompute the signature over the raw body with the same SecretKey and compare it with X-Signature to confirm that the request is authentic and intact.
The signature header is always X-Signature, and the HMAC key is your SecretKey, not the apiKey. Implement verification accordingly.

Headers

Signature calculation reference (Java)

Receiver reference (Java, with the 7-step processing convention)

1.5 Webhook common envelope

Watch the differences in field names and types: Webhook uses notificationTimestamp / eventTimestamp (Long, in milliseconds), amount and quantity fields such as freeDelta and transactionAmount are BigDecimal, and tranId is Long. The WebSocket equivalents are all string, and its time field is named timestamp (see section 2.4), so do not mix the types up when reading the two side by side.
Webhook notification example (asset movement, masked):

2. WebSocket (subscription based, ★ a DeCard-Managed differentiator)

The WebSocket channel is unique to the DeCard-Managed model: you can subscribe to a dedicated private channel to receive messages live, and replay anything you missed by version.
Real-time push over WebSocket keeps user-related changes in sync, covering KYC status, asset movements, card transactions, order status and other key information, so you can react to user activity faster.

2.1 Prerequisites and three-step integration

  1. Create a listening channel: call GET /websocket/v1/get-channel to generate a dedicated private channel for your organization. The channel string is the unique identifier used to receive messages, for example HBHmMK99SJEVMVUqCb4.
  2. Open the wss connection: substitute the channel string for {channel} in the wss address, pick mainnet or testnet according to your environment (see section 2.3), open the connection and listen for messages.
  3. Rotate channels and replay gaps: each channel lives for 24 hours and then expires. To avoid losing messages, call get-channel again before it expires; calling it an hour ahead of expiry gives the old and new channels an overlap window wide enough for a clean switchover. If you miss messages or need to replay, use GET /websocket/v1/search to look up history by version.

2.2 Channel lifecycle

WebSocket channel lifecycleWebSocket channel lifecycle
Channel security: once a new channel is generated, the old channel stops pushing data. Time the switchover correctly so you are not left waiting on a dead channel.

2.3 WebSocket environment endpoints

Replace {channel} with the channel string returned by get-channel.

2.4 WebSocket common envelope

How it differs from the Webhook envelope: WebSocket uses timestamp (a string) and carries an extra version field, and every business field inside data (amounts, quantities, tranId and so on) is a string. That differs from the Long and BigDecimal types used by Webhook, so treat this table as authoritative.
WebSocket message example (asset movement, masked):

2.5 WebSocket endpoint reference

Both endpoints return the site-wide common response envelope:
Decide success from code == "SYS_SUCCESS"; the response envelope contains no success boolean field.

Obtain a listening channel

No request parameters. data returns the private channel identifier string that belongs to your organization.

Look up historical messages by version

These two REST endpoints behave like every other REST endpoint on the site, so carry the signature headers (X-DAPI-API-KEY / X-DAPI-TIMESTAMP / X-DAPI-NONCE / X-DAPI-SIGN) as described in the Authentication Guide.

3. Business event catalogue (shared by both channels)

Both channels share the same business event types and the same data structures, eight in total. Only the envelope differs: Webhook uses notificationTimestamp / eventTimestamp (Long) while WebSocket uses timestamp plus version (string), and the field types inside data differ as described above (Webhook BigDecimal/Long ↔ WebSocket string).
Terminology: the terminal SUCCEED of CARD_APPLY is a card application status, spelled SUCCEED rather than SUCCESS, and it follows different conventions from the card order and card state machines, so do not confuse them. The NORMAL/FROZEN/CANCELLED values of CARD_STATUS are aligned with the card state machine in Card Management.

3.1 BALANCE_CHANGE digital asset movement

3.2 CARD_TRANSACTION card transactions

Today CARD_TRANSACTION distinguishes approval from decline only through response=A/D, and carries no finer-grained decline reason code; there is no declinedReason or declineCode field on the transaction query side either. Breaking the reasons down would require system changes in DCS and txn-auth. For now, work through balance, card status and risk or MCC rules one at a time.
Example (refund, with originalExternalTranId, masked):

3.3 CARD_TRANSACTION_SETTLEMENT card settlement records

The fields are broadly the same as CARD_TRANSACTION, with two differences: the settlement* fields are replaced by settledAmount (settled amount) and settledCurrencyCode (settlement currency, ISO 4217); and only direction is present, without response or the other authorization-specific fields such as systemTraceAuditNumber.

3.4 CARD_PHYSICAL_SHIPPING physical card shipping information

3.5 ORDER_STATUS FOMO top-up status

transStatus enum:

3.6 QR_ORDER_STATUS QR Pay order status

orderStatus enum:

3.7 CARD_APPLY card application status

status enum: Notes on needExtraInfo:

3.8 CARD_STATUS card status

Notifies you of the latest card status whenever it changes. Virtual card status (cardStatus) is supported today; physical card status (physicalCardStatus) will follow. cardStatus enum (aligned with the card management state machine):

4. Best practices and common questions

  • Verify first, process second: before you touch any payload, recompute HmacSHA256 over the raw body with your SecretKey and compare it with X-Signature. If verification fails, reject the request with a 401, raise an alert, and process nothing.
  • Return 200 fast, do the work asynchronously: DCS expects a response within 2 seconds. Persist the notification with its webhookId, return 200 immediately, and then process the business logic asynchronously so you never exceed the timeout and trigger needless retries.
  • Deduplicate on webhookId: retries mean the same notification can arrive more than once. Store the webhookId values you have processed and check for duplicates before processing.
  • Mind the ordering: network jitter and retries can make Webhooks arrive out of order. If you need to process events in the order they actually happened, sort by eventTimestamp (the time the event was recorded, see section 1.5) rather than by arrival time, and add a short buffering window such as 30 seconds if necessary before processing in batches.
  • Handling event types you do not care about: for event types you have no use for, simply return 200 and ignore them. Do not return an error code, because error codes trigger retries.
  • Rotate WebSocket channels early: a channel lives only 24 hours, and the old channel stops pushing as soon as a new one is generated, so call get-channel before expiry and switch over smoothly.
  • Use version as your safety net: a WebSocket connection can drop messages when the network is unstable, so reconcile regularly and backfill with GET /websocket/v1/search?version=.
  • Choose the channels you need: if delivery stability matters most, start with Webhook; if you need real-time responsiveness, front-end awareness or replay, add WebSocket. The event semantics are identical on both.
  • No sensitive card data over the real-time channels: notifications carry only the masked last 4 digits of the card number, never the full PAN or the CVV. To obtain sensitive card data, use the dedicated encrypted API (see Viewing Encrypted Card Details).

  • Authentication Guide: the two WebSocket REST endpoints behave like every other REST endpoint on the site, so carry the signature headers as described there.
  • Card Management: the conventions of the CARD_STATUS card state machine.
  • Transaction Lifecycle: understanding the two stages, authorization and settlement, behind CARD_TRANSACTION and CARD_TRANSACTION_SETTLEMENT.