Skip to main content

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: Production
Sandbox

Signature Calculation

The signature is generated by signing the concatenation of the timestamp and the raw JSON payload:
The 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: Total retry window: ~15 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. Use paymentId 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

  1. Install ngrok: npm install -g ngrok
  2. Start your local server: node server.js
  3. Expose via ngrok: ngrok http 3000
  4. Use the ngrok URL for testing: https://abc123.ngrok.io/webhooks/ceypay

Test Endpoint

Use the webhook test endpoint to verify your integration:
Response:

Troubleshooting

Webhook Not Received

Check:
  1. Webhook URL is publicly accessible (not localhost)
  2. Endpoint returns 200 status code
  3. No firewall blocking CeyPay’s IP addresses
  4. Endpoint timeout is > 10 seconds

Signature Verification Failed

Common causes:
  1. Wrong public key (ensure you use CeyPay’s public key)
  2. Body parsing issue (use raw body for verification)
  3. Timestamp not included in message
  4. Character encoding mismatch
Debug:

Multiple Webhook Deliveries

This is normal! Implement idempotency handling using paymentId.

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?