Webhooks

Webhooks are HTTP callbacks that notify your application in real-time when payment events occur. Instead of constantly polling the API to check payment status, Reevit pushes events to your server as they happen.

Understanding Webhook Architecture

Reevit handles two types of webhooks. Understanding the difference is crucial:

Inbound Webhooks (PSP → Reevit)

These are webhooks from payment providers (Paystack, Flutterwave, M-Pesa, etc.) to Reevit. Key Points:
  • Reevit handles these automatically - you don’t need to do anything
  • Configure the Reevit webhook URL in each PSP’s dashboard
  • Reevit processes provider events and updates payment status
PSP Webhook URLs:
Legacy routes such as https://api.reevit.io/webhooks/hubtel are still accepted for backwards compatibility.
You configure these URLs in the payment provider’s dashboard (e.g., Paystack Dashboard), NOT in Reevit.
For Hubtel, Reevit also injects the managed inbound callback URL automatically when creating Hubtel payment requests. Merchants should not enter a manual Hubtel callback_url per connection.

Metadata & Webhook Correlation

Reevit automatically injects the correlation metadata needed for PSP webhooks. Use metadata for your own fields like order IDs or cart IDs.
Example: API Usage

Outbound Webhooks (Reevit → Your App)

These are webhooks from Reevit to your application. Key Points:
  • You must create a webhook handler in your application
  • Configure your webhook URL in the Reevit Dashboard
  • Reevit sends you normalized events (same format regardless of PSP)
  • You verify signatures using your organization’s signing secret
This is the webhook you configure in Reevit Dashboard > Developers > Webhooks.

Why Webhooks Matter

The Problem with Polling

Without webhooks, you’d need to:
  • Poll the API every few seconds to check payment status
  • Waste server resources on unnecessary requests
  • Experience delays between payment completion and order fulfillment
  • Miss events if your polling interval is too long
Example: Customer completes payment at 10:00:00, but you only poll at 10:00:30 → 30-second delay before order fulfillment.

The Webhook Solution

With webhooks:
  • Instant notifications: Know immediately when payments succeed or fail
  • Efficient: No wasted API calls
  • Reliable: Events are delivered even if you’re not actively checking
  • Scalable: Works with thousands of payments per minute
Result: Faster order fulfillment, better customer experience, lower server costs.

How Outbound Webhooks Work

The Flow

  1. Event Occurs: Payment succeeds, fails, or changes status
  2. Reevit Sends: POST request to your webhook URL with event data
  3. Your Server Processes: Verify signature, update database, fulfill order
  4. You Respond: Return 2xx status code to acknowledge receipt

Key Concepts

  • Webhook URL: Your server endpoint that receives events
  • Signing Secret: Unique secret per organization for signature verification
  • Event Types: Different events for different payment states
  • Signatures: Cryptographic signatures to verify events are from Reevit
  • Idempotency: Events include IDs to prevent duplicate processing
  • Retries: Failed deliveries are automatically retried

Setting Up Webhooks

  1. Go to Settings → Webhooks in your Reevit dashboard
  2. Enter your webhook endpoint URL (must be HTTPS)
  3. Select which events you want to receive
  4. Copy the webhook signing secret
  5. Save configuration
Benefits:
  • Visual interface
  • Easy to update
  • See delivery status

Via API

Webhook URL Requirements

  • HTTPS only: HTTP endpoints are not supported for security
  • Publicly accessible: Must be reachable from the internet
  • Fast response: Return 2xx within 30 seconds
  • Idempotent: Handle duplicate events gracefully

Get Configuration

Response:

Event Types

Reevit sends different events for different scenarios. Subscribe only to events you need.

Payment Events

Dispute Events

The payment.disputed payload includes the provider and response_deadline (null when the PSP didn’t supply one — check the provider’s own portal). dispute.evidence_due includes dispute_id, payment_id, due_at, and threshold ("72h" or "24h" — which reminder this is). Evidence is submitted via the dispute evidence API, and a payment’s disputes are listed at GET /v1/payments/{id}/disputes.

Subscription Events

Invoice Events


Webhook Payload

Every webhook includes a consistent payload structure:

Payload Fields

  • id: Unique event identifier (use for idempotency)
  • type: Event type (e.g., payment.succeeded)
  • org_id: Your organization ID
  • created_at: When the event occurred (ISO 8601)
  • data: Event-specific data (varies by event type)

Using Event Data

Example: Fulfill Order on Payment Success

🔒 Webhook Security

Webhooks deliver sensitive payment data to your application. Follow these security practices to protect your integration.

Signature Verification (Critical)

Never process webhooks without signature verification. This is the most critical security step.
Reevit signs each webhook with HMAC-SHA256. Your server must verify this signature before processing any event. What happens without verification?
  • Attackers could send fake “payment succeeded” events
  • Orders could be fulfilled without actual payment
  • Financial losses and fraud

Anti-Replay Protection

Reebit’s webhooks include a timestamp field to prevent replay attacks:

Best Practices

  1. Always use raw request body for verification
  2. Respond quickly (under 5 seconds)
    • Return 2xx immediately after verification
    • Process events asynchronously
    • Reevit will retry failed deliveries
  3. Implement idempotent handlers
  4. Use HTTPS endpoints
    • Webhook URLs must use HTTPS
    • Reevit rejects HTTP endpoints
    • Use valid TLS certificates (not self-signed)
  5. Limit webhook IP ranges
    • Reevit webhooks come from Cloudflare IPs
    • Configure firewall to allow only these ranges

Security Checklist

Review this checklist before going live:
  • Signature verification implemented
  • Anti-replay protection (timestamp check)
  • Idempotent event handlers
  • HTTPS endpoint with valid certificate
  • Fast response time (< 5 seconds)
  • Proper error logging without sensitive data
  • Webhook secret stored securely (env vars, vault)
  • Test endpoint configured in Reevit Dashboard

Verifying Webhooks

Always verify webhook signatures. This ensures events are actually from Reevit and haven’t been tampered with.

Why Verification Matters

Without verification, attackers could:
  • Send fake payment success events
  • Trigger order fulfillment without payment
  • Cause financial losses
  • Compromise your system

How Verification Works

Reevit signs each webhook using HMAC-SHA256 with your organization’s signing secret:
  1. Header: X-Reevit-Signature: sha256=<hex-signature>
  2. Signature: HMAC-SHA256(request_body, signing_secret)
  3. Verification: Compare using constant-time comparison

Getting Your Signing Secret

Your signing secret is automatically generated when you first configure a webhook endpoint:
  1. Go to Reevit Dashboard > Developers > Webhooks
  2. Add your webhook endpoint URL
  3. Click the copy button next to “Signing Secret”
  4. Add to your environment: REEVIT_WEBHOOK_SECRET=whsec_xxx...
The signing secret is unique per organization and starts with whsec_. It’s generated once and persists across webhook URL updates.

Express.js Example

Go Example

Python (Flask) Example

PHP Example


Processing Webhooks

Best Practices

  1. Respond Quickly: Return 2xx within 30 seconds
  2. Process Async: Queue events for background processing
  3. Handle Duplicates: Use event ID for idempotency
  4. Verify Signatures: Always verify webhook authenticity
  5. Log Events: Log all events for debugging and audit

Idempotency

Events include unique IDs. Use these to prevent duplicate processing:

Error Handling

Return 2xx for success: Even if processing fails internally, return 2xx to acknowledge receipt. Process failures in background. Return 4xx/5xx for retry: Only return error codes if you want Reevit to retry:
  • 4xx: Client error (won’t retry)
  • 5xx: Server error (will retry)
Example:

Testing Webhooks

Test Events

Send a test event to verify your endpoint:
Use Cases:
  • Initial setup: Verify endpoint is working
  • After changes: Test after updating webhook URL
  • Debugging: Test signature verification

Local Development

For local development, use tools like:
  • ngrok: Expose local server to internet
  • webhook.site: Temporary webhook URLs for testing
  • Stripe CLI: Forward webhooks to local server
Example with ngrok:

Viewing Webhook Events

List Events

Use Cases:
  • Debugging: See what events were sent
  • Audit: Review event history
  • Monitoring: Check event delivery

Get Single Event

Use Cases:
  • Investigation: Review specific event details
  • Replay: Get event data for replaying

Replaying Events

Re-send a webhook event if delivery failed or you need to reprocess:
Use Cases:
  • Failed delivery: Retry after fixing endpoint
  • Reprocessing: Reprocess event after bug fix
  • Testing: Test event processing logic

Delivery Status

View Delivery Attempts

Response:

Delivery Statuses

  • delivered: Successfully delivered and acknowledged
  • pending: Queued for delivery
  • failed: Failed after all retry attempts
  • retrying: Currently retrying after failure

Retry Behavior

Reevit automatically retries failed webhook deliveries with exponential backoff: After 5 failed attempts, the event is marked as failed and won’t be retried automatically.

Why Retries Matter

  • Network issues: Temporary network problems resolve themselves
  • Server restarts: Your server may be restarting
  • Rate limiting: Temporary rate limits may clear
  • Transient errors: Some errors are temporary
Best Practice: Make your webhook endpoint idempotent so retries are safe.

Security Best Practices

  1. Always Verify Signatures: Never process unverified webhooks
  2. Use HTTPS: Only accept webhooks over HTTPS
  3. Validate Event Data: Don’t trust event data blindly
  4. Rate Limiting: Implement rate limiting on webhook endpoint
  5. Monitor Failures: Alert on repeated webhook failures
  6. Keep Secrets Secure: Never expose webhook secrets
  7. Use Idempotency: Handle duplicate events gracefully

Common Patterns

Order Fulfillment

Subscription Management

Refund Processing

Failed Payment Handling


Troubleshooting

Webhooks Not Received

  1. Check URL: Verify webhook URL is correct and accessible
  2. Check HTTPS: Ensure URL uses HTTPS
  3. Check Firewall: Ensure firewall allows Reevit IPs
  4. Check Logs: Review delivery logs for errors
  5. Test Endpoint: Use test endpoint to verify connectivity

Signature Verification Failing

  1. Check Secret: Verify webhook secret is correct
  2. Check Payload: Ensure you’re using raw request body
  3. Check Encoding: Ensure proper string encoding
  4. Check Headers: Verify signature header name

Duplicate Events

  1. Use Event IDs: Check event ID before processing
  2. Implement Idempotency: Make handlers idempotent
  3. Check Retries: Verify retry logic isn’t causing duplicates

Next Steps

Payments

See how payment intents, statuses, and refunds work end-to-end.

Subscriptions

Set up automated recurring billing and dunning policies.

Workflows

Automate actions based on payment and webhook events.

API Reference

Review endpoint schemas and headers for webhook setup and retries.