{
"id": "8e2d6a1f-3c4b-4d5e-8f9a-0b1c2d3e4f5a",
"type": "payment.paid",
"createdAt": "2026-10-14T09:31:40.120Z",
"data": {
"paymentId": "0f4c1e2a-7b3d-4e5f-9a6b-1c2d3e4f5a6b",
"appId": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
"amount": 5.43,
"assetIdentifier": "USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"status": "Paid",
"transactionHash": "7d3f9c1b4a2e8f6d0c5b9a7e3d1f2c4b6a8e0d9f7c5b3a1e2d4f6c8b0a9e7d3f",
"clientReferenceId": "order_18421"
}
}Payment webhook
Sent to your webhook URL when a payment reaches a final state. The same envelope is used for payment.paid, payment.failed and payment.expired; the type field and the Paywit-Event-Type header tell them apart. Delivery is at-least-once with retries, so deduplicate on id. Verify the Paywit-Signature header before trusting the body. See the webhooks guide.
{
"id": "8e2d6a1f-3c4b-4d5e-8f9a-0b1c2d3e4f5a",
"type": "payment.paid",
"createdAt": "2026-10-14T09:31:40.120Z",
"data": {
"paymentId": "0f4c1e2a-7b3d-4e5f-9a6b-1c2d3e4f5a6b",
"appId": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
"amount": 5.43,
"assetIdentifier": "USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"status": "Paid",
"transactionHash": "7d3f9c1b4a2e8f6d0c5b9a7e3d1f2c4b6a8e0d9f7c5b3a1e2d4f6c8b0a9e7d3f",
"clientReferenceId": "order_18421"
}
}Authorizations
Server-to-server key, sk_test_... on sandbox and sk_live_... on production. Generate it in the dashboard under your app. Never ship it to a browser or mobile app.
Headers
t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>" keyed with your whsec_ secret>
Unique event id. Same value as id in the body.
payment.paid, payment.failed, payment.expired Body
Response
Return any 2xx within 10 seconds to acknowledge. Anything else, or a timeout, is retried up to 6 times over about a day.