Overview
Webhooks enable you to receive automatic notifications when:- A payment is initiated
- A customer completes payment
- A payment is under user review
- A payment expires
- A payment fails
Webhook Events
payment.initiated
Triggered when a payment is created.payment.user_review
Triggered when a customer loads the payment QR code in their wallet app (currently supported for Bybit Pay only). This indicates the customer is actively viewing the payment.payment.paid
Triggered when a customer successfully completes payment.payment.expired
Triggered when a payment link expires without payment.payment.failed
Triggered when a payment fails.Webhook Headers
Every webhook request includes these headers:- X-Webhook-Signature: Base64-encoded ED25519 signature for verification
- X-Webhook-Timestamp: Unix timestamp in milliseconds
- X-Webhook-Attempt: Current delivery attempt (1-5)
Signature Verification
IMPORTANT: Always verify webhook signatures to prevent unauthorized requests. CeyPay uses ED25519 (an EdDSA signature scheme) for signing webhooks.CeyPay Public Keys
Use these public keys to verify the signatures sent by CeyPay: ProductionSignature Calculation
The signature is generated by signing the concatenation of the timestamp and the raw JSON payload:X-Webhook-Signature header contains the Base64-encoded signature.
Implementation Examples
Node.js / Express
Python / Flask (using cryptography)
PHP
Retry Policy
CeyPay implements exponential backoff for failed webhook deliveries:| Attempt | Delay After Previous |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 2 minutes |
| 4 | 4 minutes |
| 5 | 8 minutes |
When Are Webhooks Retried?
Webhooks are retried when:- Connection timeout (10 seconds)
- HTTP status code is not 2xx (200-299)
- Network error occurs
When Do Retries Stop?
Retries stop when:- Webhook responds with 2xx status code
- Maximum attempts (5) reached
- 15 minutes elapsed since first attempt
Best Practices
1. Respond Quickly
Return a 200 status code immediately, then process asynchronously:2. Handle Idempotency
You may receive the same webhook multiple times. UsepaymentId to track processed webhooks:
3. Use HTTPS
Always use HTTPS for webhook endpoints. CeyPay will reject insecure HTTP URLs in production.4. Validate Timestamp
Reject webhooks with old timestamps to prevent replay attacks:5. Log Everything
Maintain detailed logs for debugging:Testing Webhooks
Local Development with ngrok
- Install ngrok:
npm install -g ngrok - Start your local server:
node server.js - Expose via ngrok:
ngrok http 3000 - Use the ngrok URL for testing:
https://abc123.ngrok.io/webhooks/ceypay
Test Endpoint
Use the webhook test endpoint to verify your integration:Troubleshooting
Webhook Not Received
Check:- Webhook URL is publicly accessible (not localhost)
- Endpoint returns 200 status code
- No firewall blocking CeyPay’s IP addresses
- Endpoint timeout is > 10 seconds
Signature Verification Failed
Common causes:- Wrong public key (ensure you use CeyPay’s public key)
- Body parsing issue (use raw body for verification)
- Timestamp not included in message
- Character encoding mismatch
Multiple Webhook Deliveries
This is normal! Implement idempotency handling usingpaymentId.
Webhook Timeout
Ensure your endpoint responds within 10 seconds:- Return 200 immediately
- Process webhook asynchronously
- Optimize database queries
Example Implementations
E-commerce Order Fulfillment
Subscription Activation
Support
Need help with webhook integration?- Email: [email protected]
- Documentation: https://docs.ceypay.io
- Status page: https://status.ceypay.io