Skip to main content

Payment Webhooks

GatePass uses webhooks to notify your application when payment events occur. Payment webhooks are sent by payment providers (Paystack and Flutterwave) to confirm successful transactions and trigger ticket minting.
All webhook endpoints must validate signatures before processing. See Webhook Verification for security best practices.

Paystack Webhook

Receive payment notifications from Paystack.

Endpoint

POST /api/webhooks/paystack

Headers

x-paystack-signature
string
required
HMAC SHA512 signature of the request body using your Paystack secret key
Content-Type
string
default:"application/json"
Request content type

Webhook Events

GatePass processes the following Paystack webhook events:
EventDescription
charge.successPayment was successfully charged

Request Body

event
string
required
The event type (e.g., charge.success)
data
object
required
Payment transaction data
data.reference
string
required
Unique payment reference matching the order
data.id
string
required
Paystack transaction ID
data.amount
number
Amount paid in kobo (₦100 = 10000 kobo)
data.status
string
Payment status (e.g., success)
data.customer
object
Customer information

Response

ok
boolean
Webhook acknowledgment status

Example Webhook Payload

{
  "event": "charge.success",
  "data": {
    "id": 1234567890,
    "reference": "ord_abc123xyz456",
    "amount": 50000,
    "currency": "NGN",
    "status": "success",
    "paid_at": "2026-03-06T10:30:00.000Z",
    "customer": {
      "id": 98765,
      "email": "[email protected]",
      "customer_code": "CUS_xyz123"
    },
    "authorization": {
      "card_type": "visa",
      "last4": "4081",
      "bank": "Test Bank"
    }
  }
}

Security Verification

Paystack webhooks use HMAC SHA512 signatures for verification:
Signature Verification
const crypto = require('crypto');

const secret = process.env.PAYSTACK_SECRET_KEY;
const signature = request.headers['x-paystack-signature'];
const hash = crypto
  .createHmac('sha512', secret)
  .update(request.body)
  .digest('hex');

if (hash === signature) {
  // Webhook is authentic
}
Source: /src/packages/server/src/routes/webhooks.ts:88-89

Flutterwave Webhook

Receive payment notifications from Flutterwave.

Endpoint

POST /api/webhooks/flutterwave

Headers

verif-hash
string
required
Secret hash for webhook verification (matches FLW_SECRET_HASH environment variable)
Content-Type
string
default:"application/json"
Request content type

Webhook Events

GatePass processes the following Flutterwave webhook events:
EventDescription
charge.completedPayment transaction completed (check data.status for success)

Request Body

event
string
required
The event type (e.g., charge.completed)
data
object
required
Payment transaction data
data.tx_ref
string
required
Unique transaction reference matching the order
data.id
string
required
Flutterwave transaction ID
data.status
string
required
Payment status (e.g., successful, failed)
data.amount
number
Amount paid
data.currency
string
Payment currency (e.g., NGN, USD)
data.customer
object
Customer information

Response

ok
boolean
Webhook acknowledgment status

Example Webhook Payload

{
  "event": "charge.completed",
  "data": {
    "id": 9876543210,
    "tx_ref": "ord_def789ghi012",
    "flw_ref": "FLW_MOCK_REF",
    "amount": 5000,
    "currency": "NGN",
    "status": "successful",
    "payment_type": "card",
    "created_at": "2026-03-06T11:45:00.000Z",
    "customer": {
      "id": 54321,
      "email": "[email protected]",
      "name": "John Doe"
    },
    "card": {
      "first_6digits": "539983",
      "last_4digits": "8381",
      "type": "MASTERCARD"
    }
  }
}

Security Verification

Flutterwave webhooks use a secret hash for verification:
Signature Verification
const signature = request.headers['verif-hash'];
const secretHash = process.env.FLW_SECRET_HASH;

if (signature === secretHash) {
  // Webhook is authentic
}
Source: /src/packages/server/src/utils/flutterwave.ts:58-61

Webhook Processing Flow

When a payment webhook is received and verified, GatePass performs the following actions:
  1. Validate Signature - Verify webhook authenticity using HMAC/secret hash
  2. Find Order - Locate the order using the payment reference
  3. Update Payment Status - Mark order as COMPLETED and store transaction ID
  4. Mint NFT Tickets - If event has a contract address, mint tickets on blockchain
  5. Create Tickets - Store ticket records with token IDs and transaction hash
  6. Send Notification - Notify user of successful purchase
Webhook endpoints must be publicly accessible and respond with 200 status codes. Failed webhooks may be retried by payment providers.

Testing Webhooks

Using ngrok for Local Development

# Expose local server
grok http 3000

# Set webhook URL in payment provider dashboard
https://your-ngrok-url.ngrok.io/api/webhooks/paystack

Manual Testing

curl -X POST http://localhost:3000/api/webhooks/paystack \
  -H "Content-Type: application/json" \
  -H "x-paystack-signature: YOUR_SIGNATURE" \
  -d '{
    "event": "charge.success",
    "data": {
      "reference": "test_ref_123",
      "id": 123456,
      "amount": 50000,
      "status": "success"
    }
  }'

Error Handling

Status CodeDescription
200Webhook processed successfully
401Invalid or missing signature
500Server configuration error (missing secret key)

Best Practices

  • Always verify webhook signatures before processing
  • Respond quickly (within 5 seconds) to avoid retries
  • Implement idempotency to handle duplicate webhooks
  • Log webhook payloads for debugging and audit trails
  • Use environment variables for secret keys
  • Monitor webhook delivery in payment provider dashboards

Webhook Verification

Learn how to securely verify webhook signatures

Orders API

Manage ticket orders and payments

Build docs developers (and LLMs) love