# Verify signatures

Product: PNSL API
Guides follow API reference 2.0.0 and event reference 1.0.0.
Canonical page: https://docs.axiym.io/pnsl-api/webhooks/verifying-signatures

Every delivery is signed. Verify it before trusting the payload.

## Headers

| Header        | Value                                                  |
| ------------- | ------------------------------------------------------ |
| `X-Signature` | Base64 Ed25519 signature of the raw request body.      |
| `X-Key-Id`    | Identifier of the public key that signed the delivery. |
| `X-Algorithm` | `Ed25519`.                                             |

## Steps

1. Keep the raw request body exactly as received; verify the bytes, not a
   re-serialized JSON.
2. Read `X-Key-Id` and fetch the key with
   `GET /webhooks/public-keys/{publicKeyId}`. Check that it is `active`.
   Cache keys by id; `X-Key-Id` changes when Axiym rotates keys.
3. Verify the Ed25519 signature in `X-Signature` over the raw body with that
   key.
4. If the headers are missing or the signature does not verify, respond
   `401` and do not process the event.
5. Deduplicate verified events by `id` to prevent repeated processing. Retries
   retain the original payload and timestamp. If you enforce a timestamp age
   limit, agree on the supported delivery and retry window with Axiym first;
   an arbitrary short window can reject legitimate delayed deliveries.

## Example delivery

```json
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "timestamp": "2026-06-23T14:05:09Z",
  "type": "credit-account.created",
  "data": {
    "creditAccountId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "clientId": "b7e8c1a2-9f43-4d2e-8a6b-1c2d3e4f5a6b",
    "code": "AXI000221",
    "currency": "USD",
    "creditLimit": "10000.00",
    "principalOutstanding": "0.00",
    "totalRepaymentAmount": "0.00",
    "totalInterestAmount": "0.00",
    "availableBalance": "10000.00",
    "paymentRails": "ZENUS_BANK",
    "status": "ACTIVE"
  }
}
```
