Cripay Docs

Webhooks

Signed events for every payment and payout transition, with retries, a delivery log and replay.

Endpoint

POST /v1/webhook-endpoints { url, enabled_events? } returns the endpoint with its secret (whsec_…) once. Empty enabled_events receives everything. Up to 16 active endpoints; private, loopback and link-local URLs are refused.

Delivery

Each event is a POST with a JSON body and headers:

HeaderValue
X-CryptoPay-Signaturev1=<hex>; HMAC-SHA256 of "{timestamp}.{raw body}" with the secret. Two v1= values for 24 h after a rotation (POST /v1/webhook-endpoints/:id/rotate-secret; pass { "revoke_previous": true } when the old secret leaked, or DELETE /v1/webhook-endpoints/:id/previous-secret to end an overlap early).
X-CryptoPay-TimestampUnix seconds. Reject if older than 5 minutes.
X-CryptoPay-Event-Id, X-CryptoPay-Event-Type, X-CryptoPay-AttemptDedupe key, type, attempt number.

Body: { id: "evt_…", object: "event", type, mode, created_at, data: { payment_intent | payout } }. Endpoints belong to one mode: an endpoint created with a test key (or with the console in test mode) only receives mode: "test" events, a live endpoint only mode: "live". Still check mode in your handler before fulfilling an order, and store id to ignore a redelivery of an event you already processed. Respond 2xx within a few seconds; non-2xx responses are retried at 1 m, 5 m, 30 m, 2 h, 6 h, 12 h and 24 h, after which the delivery is failed and the endpoint is marked failing after 10 consecutive failures.

Events: payment.created, payment.processing, payment.confirmed, payment.underpaid, payment.overpaid, payment.expired, payment.failed, payment.held, payout.created, payout.confirmed, payout.failed, test.ping.

Verify

Node (@cryptopay/sdk):

const event = constructEvent({ rawBody, signature: headers["x-cryptopay-signature"], timestamp: headers["x-cryptopay-timestamp"], secret });

Other languages

Dependency-free verifiers for Python and PHP, checked against the same fixture as the SDK, live in the repository under examples/webhooks/ together with minimal receivers.

Delivery log and replay

GET /v1/webhook-deliveries lists every attempt with the signed request body, the response status and the error; POST /v1/webhook-deliveries/:id/retry re-queues a finished delivery (fresh timestamp and signature). POST /v1/webhook-endpoints/:id/test sends a test.ping through the normal pipeline.

On this page