Verifying signatures
Axiym signs the raw HTTP request body. Verify the signature before trusting or processing the event.
Do not parse and re-serialize JSON for verification. Whitespace, field order, or encoding changes produce different bytes and cause verification to fail.
Verification steps
- Capture the raw body bytes before JSON parsing.
- Read
X-Signature,X-Key-Id, andX-Algorithm. - Reject the request unless
X-AlgorithmisEd25519. - Load the cached public key for
X-Key-Id, or retrieve it from the API. - Verify the base64 signature against the raw body.
- Parse the JSON only after verification succeeds.
- De-duplicate by the event
id.
Return a non-2xx response when verification fails.
JavaScript example
import { createPublicKey, verify } from "node:crypto";
export function verifyAxiymWebhook(rawBody, headers, keyResponse) {
const signature = headers["x-signature"];
const keyId = headers["x-key-id"];
const algorithm = headers["x-algorithm"];
if (!signature || !keyId || algorithm !== "Ed25519") return false;
if (keyResponse.publicKeyId !== keyId) return false;
const publicKey = createPublicKey({
key: Buffer.from(keyResponse.publicKey, "base64"),
format: "der",
type: "spki",
});
return verify(
null,
rawBody,
publicKey,
Buffer.from(signature, "base64"),
);
}Operational checks
- Cache keys by
publicKeyIdso signing-key rotation is safe. - Validate the event timestamp against your accepted clock-skew window.
- Persist event IDs so de-duplication survives restarts.
- Return
2xxonly after durable persistence or queueing. - Fetch the current payout if ordering or current state matters.