> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thedecard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook configuration

> Fills in self-service configuration and HMAC signature verification.

## 📄 Guide

Whether you are an exchange, a wallet or a platform, webhooks let you mirror the key DCS events, card lifecycle, transaction authorization, KYC and tickets, into your own system in real time, without the cost of polling. As a licensed issuer, DCS signs every webhook it sends, so verifying the signature is all it takes to confirm that an event really came from DCS.

This page covers two things: **how to get DCS to push events to your callback URL** (configuration and whitelisting), and **how to verify that each push is genuine** (the HMAC signature). For the event types and the field structure of each event, see [Events and data structures](./events-and-schema).

## 1. Configure the callback URLs

<Warning>
  **Who does it**: webhook configuration is currently done by **DCS** on your behalf; there is no self-service configuration endpoint yet. Please send the information below through your integration group chat or your business contact.
</Warning>

There are two callback URLs to give DCS:

| URL          | Purpose                                | What is pushed                                                                                  |
| ------------ | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `webhookUrl` | Business event notifications           | Card order status, card status, KYC tickets, tickets, authorization results (asynchronous)      |
| `authUrl`    | Authorization forwarding notifications | Real-time authorization requests (DCS waits synchronously for you to return approve or decline) |

> `authUrl` carries the **real-time decision** under Partner-Managed and is protected by RSA two-way signing and encryption, which makes it a channel entirely separate from the business webhooks (HMAC-signed) described on this page. For the security model of `authUrl`, see [Real-time authorization](../transactions/authorization); for how to hand over the callback URLs and the public key, see [First steps](../../getting-started/first-steps).

### Requirements for the callback URLs

* They must use `https` and resolve to an IP that is **reachable from the public internet**.
* They must be registrable in the DCS webhook **whitelist**, so send DCS your **egress addresses** as well (separately for sandbox and production).
* Expose a **stable, long-lived** path; URLs that change often lead to missed deliveries.

<Warning>
  **Who does it (you)**: DCS operates a webhook whitelist. Sandbox and production are two independent configurations, so submit the addresses for each; otherwise you will find a gap on go-live day.
</Warning>

## 2. Verify the signature (HMAC-SHA256)

To keep the channel secure, DCS includes `X-Signature` in the headers of **every** webhook request. The signature is produced with `HmacSHA256` using your `secretKey` as the key. Before you process the payload you must recompute the signature over the **raw payload as received** with the same algorithm and confirm that it matches `X-Signature`; only then is the request proven genuine and untampered.

### Request headers

| Header         | Description                                                               |
| -------------- | ------------------------------------------------------------------------- |
| `X-Signature`  | The HMAC-SHA256 signature DCS computed over the raw payload (hex encoded) |
| `Content-Type` | Always `application/json`                                                 |

<Warning>
  **Always compute over the raw bytes**: the HMAC has to be computed over the **raw payload string** DCS sent. If you parse the JSON and regenerate it, field order, whitespace and escaping can all change, the signature will differ and verification will fail. Read and buffer the raw body for verification **before** you parse it. DCS sends compact JSON with the fields at every level sorted lexicographically by full field name, and new fields may be added in the future — none of this affects verification as long as you verify the raw payload. See [Events and schema · Notes](./events-and-schema#notes).
</Warning>

### Verification example

The Java example DCS provides (computing the HMAC-SHA256 of the payload):

```java theme={null}
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

class HmacSignature {

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        String secretKey = "secret_key";
        String webhookPayloadStr = "webhook_Payload_Str"; // the raw payload string as received
        byte[] hmacSha256;
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(secretKeySpec);
        hmacSha256 = mac.doFinal(webhookPayloadStr.getBytes());
        // compare against the X-Signature request header
        System.out.println(Hex.encodeHexString(hmacSha256));
    }
}
```

The check passes when `Hex(HmacSHA256(secretKey, raw payload))` and `X-Signature` are **identical character for character**. Use a constant-time comparison to avoid a timing side channel.

> `secretKey` comes from the same source as `apiKey`; together they are the integration credentials DCS issues to you. For how to retrieve them securely for production, see [Authentication](../../integration-resources/authentication). Treat `secretKey` as a secret, keep it server-side only, and never ship it to a front end or a client app.

## 3. Response and consumption conventions

So that no event is lost and none is processed twice, we recommend the following conventions:

| Item                     | Convention                                    | Notes                                                                                                                                                                              |
| ------------------------ | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Success response         | Return HTTP `200` (any 2xx counts as success) | Acknowledge quickly on receipt, then process the business logic asynchronously, to avoid timing out                                                                                |
| Idempotent deduplication | Key on `webhookId`                            | The same event may be delivered more than once, so check `webhookId` for duplicates before processing                                                                              |
| Retry on failure         | Up to 3 attempts for general events           | Driven by a scheduled job, with the backoff interval following that job's configuration; the real-time `AUTHORISATION` channel is never retried and a timeout is declined outright |
| Out-of-order arrival     | Order by `notificationTime`                   | The network and retries can deliver events out of order, so use the timestamp in the payload to reconstruct the true sequence                                                      |

> For the meaning of the shared fields such as `webhookId` and `notificationTime`, see [Events and data structures](./events-and-schema#common-envelope-structure).

<Warning>
  **Avoid returning an HTML or plain-text error page**: return a structured response even when processing fails (or acknowledge with `2xx` and retry asynchronously); it makes troubleshooting and redelivery tracking far easier.
</Warning>

## Next steps

Once signature verification works end to end, move on to [Events and data structures](./events-and-schema), parse each event's `data` field by `webhookType`, and wire it into your business logic.
