Webhook Security
Webhook Security
Knova sends webhook notifications as POST requests to each active subscription URL. The headers below protect notifications Knova sends to you. To protect your own calls to Knova, see API Authentication.
Each request can carry two independent security headers:
| Header | Purpose |
|---|---|
x-signature | Proves the body came from your Knova deployment and was not altered in transit |
x-api-key | Shared secret sent by Knova, which you can check before doing any other work |
Both are enabled per deployment, not per subscription, and apply to every subscription in that deployment. Ask your Knova contact which headers are enabled for your deployment.
Request shape
POST <subscription url>
Content-Type: application/json
x-signature: <base64 signature of the body>
x-api-key: <shared secret>
{"id":"…","uetr":"…","event_type":"Final","created":"2026-01-01T00:00:00Z","payload":{…}}
| Field | Meaning |
|---|---|
id | Event ID. Stays the same across retries and resends, so use it to deduplicate. |
uetr | Unique end-to-end transaction reference, or null. |
event_type | One of Initial, DigitalTwin, Onchain, Fiat, Final, and ApprovalRequest when approvals are enabled. |
created | Time this delivery attempt was built. It changes on every attempt, so the body and its signature change between retries. |
payload | Event data. Its shape depends on event_type. |
x-signature: payload signing
x-signature: payload signingWhat is signed
The signature covers the exact raw request body bytes, with no prefix, timestamp, or nonce. Verify against the raw bytes as received. If you parse and re-serialize the JSON first, key order or whitespace can change and verification will fail.
Algorithm and encoding
The scheme depends on the type of the key Knova signs with:
| Key type | Signature scheme | Hash |
|---|---|---|
| RSA | RSASSA-PKCS1-v1_5 | SHA-512 |
EC (e.g. P-256 / prime256v1) | ECDSA, DER-encoded signature | SHA-512 |
| Ed25519 | Ed25519 (pure, no pre-hash) | n/a |
The signature is encoded as standard base64 with padding (not URL-safe).
Public key
Knova gives you the public key in PEM format out of band; no endpoint serves it. Requests do not carry a key ID, so during a key rotation accept signatures from both the old and new public keys until the change is complete.
Verifying a signature
- Read the raw request body bytes before parsing them.
- Base64-decode the
x-signatureheader. - Verify the signature over the raw body with the Knova public key, using the scheme for its key type.
- Reject the request (for example with
401) if the header is missing or verification fails. Only then parse the JSON. - Deduplicate on
id, and reject events whosecreatedis too old.
Example with openssl:
echo -n "$X_SIGNATURE" | base64 -d > signature.bin
# body.json must contain the exact bytes received
# RSA or EC
openssl dgst -sha512 -verify knova_public_key.pem -signature signature.bin body.json
# Ed25519
openssl pkeyutl -verify -pubin -inkey knova_public_key.pem -rawin -in body.json -sigfile signature.binx-api-key: shared secret
x-api-key: shared secretWhen enabled, every request carries an x-api-key header with a secret value agreed with Knova. This is a secret Knova sends to you. It is not the API key you send to Knova on API calls.
- Scope: one value per deployment, sent to every subscription.
- Checking it: compare the header with the expected value using a constant-time comparison, and reject the request if it is missing or does not match.
- Rotation: accept both the old and new values while the change rolls out.
The API key only shows that the caller knows a shared secret. It does not protect the body from tampering or replay. Use it together with x-signature, not instead of it.
Delivery behavior that affects verification
- Success: only HTTP
200counts as delivered. Any other status, including other 2xx codes, is retried. - Retries: failed deliveries are retried with exponential backoff, up to 512 seconds between attempts.
- Re-signing:
createdchanges on every attempt, so each retry has a new body and signature. Deduplicate onid, not on the signature. - Resends: a notification can be resent on request. A resend carries the same
id.
Updated about 7 hours ago
