Skip to main content

Payment API Service

The Payment API Service is the main gateway for processing payments. It orchestrates card tokenization, fraud detection, and transaction processing while providing a simple REST API for merchants.
Base URL: https://paymentgateway.redahaloubi.com/api/v1Public API: https://paymentgateway.redahaloubi.com/api/public

Authentication

The Payment API uses two different authentication methods depending on the endpoint:
Use for: Payment processing from your backend server
X-API-Key: pk_live_abc123def456...
Endpoints requiring API Key:
  • /api/v1/payments/* - All payment operations
  • /api/v1/transactions/* - Transaction queries
  • /api/v1/payment-intents - Create payment intent
  • /api/v1/payment-intents/:id/cancel - Cancel payment intent
How to get an API key: See Merchant API β†’ Create API Key

Rate Limits

Payment Operations

20 requests per second per merchant10,000 requests per hour per merchant

Transaction Queries

100 requests per second per merchant

Public Endpoints

50 requests per second per IPUsed for hosted checkout page

Idempotency Cache

24 hour cache durationPrevents duplicate payments

Payment Flow Overview


Payment Operations

Authorize Payment

POST
endpoint
/api/v1/payments/authorize
Authorize a payment by holding funds on the customer’s card without charging. Authorization is valid for 7 days. Authentication: API Key required Request Body
amount
integer
required
Amount in cents (e.g., 9999 = $99.99)Min: 1 (0.01 in currency)Max: No limit (dependent on card)
currency
string
required
Three-letter currency codeSupported: USD, EUR, MADLength: Exactly 3 characters
card
object
required
Card details
customer
object
Customer information (optional)
description
string
Payment description (e.g., β€œOrder #12345”)
metadata
object
Custom key-value pairs for your referenceExample: {"order_id": "12345", "customer_id": "cus_abc"}
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payments/authorize \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-12345-auth" \
  -d '{
    "amount": 9999,
    "currency": "USD",
    "card": {
      "number": "4242424242424242",
      "cardholder_name": "John Doe",
      "exp_month": 12,
      "exp_year": 2027,
      "cvv": "123"
    },
    "customer": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "description": "Order #12345 - Premium Plan",
    "metadata": {
      "order_id": "12345",
      "plan": "premium"
    }
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_abc123def456ghi789",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "fraud_score": 15,
    "fraud_decision": "approve",
    "response_code": "00",
    "response_message": "Approved",
    "transaction_id": "txn_xyz789uvw012rst345",
    "created_at": "2026-01-24T10:00:00Z",
    "expires_at": "2026-01-31T10:00:00Z"
  }
}
400 Bad Request - Invalid Amount
{
  "success": false,
  "error": "invalid request: amount must be at least 1"
}
400 Bad Request - Unsupported Currency
{
  "success": false,
  "error": "unsupported currency (only USD, EUR, and MAD supported)"
}
402 Payment Required - Card Declined
{
  "success": false,
  "error": "payment declined: insufficient funds (code: 51)"
}
402 Payment Required - Fraud Declined
{
  "success": false,
  "error": "payment declined: high fraud risk (score: 85)"
}
409 Conflict - Idempotency Key Mismatch
{
  "success": false,
  "error": "idempotency key already used with different request data"
}
429 Too Many Requests
{
  "success": false,
  "error": "rate limit exceeded: 20 requests per second"
}
Idempotency: Include an Idempotency-Key header to safely retry requests. If the same key is used within 24 hours, the original response is returned without creating a new payment.

Sale Payment

POST
endpoint
/api/v1/payments/sale
Process a sale (authorize + capture in one step). Funds are immediately charged to the customer’s card. Authentication: API Key required Request Body Same as Authorize Payment Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payments/sale \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-12345-sale" \
  -d '{
    "amount": 4999,
    "currency": "USD",
    "card": {
      "number": "5555555555554444",
      "cardholder_name": "Jane Smith",
      "exp_month": 6,
      "exp_year": 2028,
      "cvv": "456"
    },
    "description": "Subscription - Monthly Plan"
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_def456ghi789jkl012",
    "status": "captured",
    "amount": 4999,
    "currency": "USD",
    "card_brand": "mastercard",
    "card_last4": "4444",
    "auth_code": "789012",
    "response_code": "00",
    "response_message": "Approved",
    "transaction_id": "txn_mno345pqr678stu901",
    "created_at": "2026-01-24T10:05:00Z",
    "captured_at": "2026-01-24T10:05:01Z"
  }
}
When to use Sale vs Authorize:Use Sale when:
  • Immediate charge is required (subscriptions, digital goods)
  • You ship goods immediately
  • Payment and fulfillment happen together
Use Authorize when:
  • You need to verify funds availability first
  • You ship physical goods later
  • You need to adjust the amount before capture
  • You want to manually review orders

Capture Payment

POST
endpoint
/api/v1/payments/:id/capture
Capture a previously authorized payment. You can capture the full amount or a partial amount. Authentication: API Key required Path Parameters
id
string
required
Payment ID from authorization response
Request Body
amount
integer
required
Amount to capture in centsMust be: ≀ authorized amountPartial captures: Allowed (e.g., capture 50of50 of 100 authorization)
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payments/pay_abc123def456/capture \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 9999
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_abc123def456ghi789",
    "status": "captured",
    "amount": 9999,
    "currency": "USD",
    "captured_amount": 9999,
    "card_brand": "visa",
    "card_last4": "4242",
    "captured_at": "2026-01-24T15:30:00Z"
  }
}
400 Bad Request - Already Captured
{
  "success": false,
  "error": "payment already captured"
}
400 Bad Request - Amount Too High
{
  "success": false,
  "error": "capture amount exceeds authorized amount"
}
400 Bad Request - Authorization Expired
{
  "success": false,
  "error": "authorization expired (valid for 7 days)"
}
404 Not Found
{
  "success": false,
  "error": "payment not found"
}
Capture Deadline: Authorizations expire after 7 days. Capture before the expiration date or the authorization will be automatically voided.

Void Payment

POST
endpoint
/api/v1/payments/:id/void
Cancel an authorized payment before it’s captured. This releases the hold on the customer’s card. Authentication: API Key required Path Parameters
id
string
required
Payment ID to void
Request Body
reason
string
required
Reason for voiding (for audit logs)Example: β€œCustomer requested cancellation”, β€œOrder canceled”
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payments/pay_abc123def456/void \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Customer requested order cancellation"
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_abc123def456ghi789",
    "status": "voided",
    "amount": 9999,
    "currency": "USD",
    "voided_at": "2026-01-24T12:00:00Z",
    "void_reason": "Customer requested order cancellation"
  }
}
400 Bad Request - Already Captured
{
  "success": false,
  "error": "cannot void captured payment (use refund instead)"
}
400 Bad Request - Already Voided
{
  "success": false,
  "error": "payment already voided"
}
Void vs Refund:Void: Cancel before capture (no money has been charged)
Refund: Return money after capture (money has been charged)

Refund Payment

POST
endpoint
/api/v1/payments/:id/refund
Refund a captured payment. Supports full and partial refunds. Authentication: API Key required Path Parameters
id
string
required
Payment ID to refund
Request Body
amount
integer
required
Amount to refund in centsFull refund: Original payment amountPartial refund: Less than original amount
reason
string
required
Refund reason (for audit logs)Example: β€œProduct returned”, β€œService not delivered”
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payments/pay_abc123def456/refund \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2500,
    "reason": "Product damaged - partial refund"
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_abc123def456ghi789",
    "status": "partially_refunded",
    "amount": 9999,
    "currency": "USD",
    "refunded_amount": 2500,
    "remaining_amount": 7499,
    "refunded_at": "2026-01-24T16:00:00Z",
    "refund_reason": "Product damaged - partial refund"
  }
}
400 Bad Request - Not Captured
{
  "success": false,
  "error": "can only refund captured payments"
}
400 Bad Request - Amount Too High
{
  "success": false,
  "error": "refund amount exceeds available amount"
}
400 Bad Request - Already Refunded
{
  "success": false,
  "error": "payment already fully refunded"
}
Refund Processing:
  • Refunds are processed immediately
  • Funds typically appear in customer’s account within 5-10 business days
  • Multiple partial refunds are supported until full amount is refunded

Get Payment

GET
endpoint
/api/v1/payments/:id
Retrieve details of a specific payment. Authentication: API Key required Path Parameters
id
string
required
Payment ID
Example Request
curl -X GET https://paymentgateway.redahaloubi.com/api/v1/payments/pay_abc123def456 \
  -H "X-API-Key: pk_live_your_api_key"
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pay_abc123def456ghi789",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "description": "Order #12345 - Premium Plan",
    "customer": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "metadata": {
      "order_id": "12345",
      "plan": "premium"
    },
    "created_at": "2026-01-24T10:00:00Z",
    "expires_at": "2026-01-31T10:00:00Z"
  }
}
404 Not Found
{
  "success": false,
  "error": "payment not found"
}
401 Unauthorized - Wrong Merchant
{
  "success": false,
  "error": "payment not found"
}

Payment Intents

Payment Intents provide a hosted checkout solution where customers complete payment in a browser.

Create Payment Intent

POST
endpoint
/api/v1/payment-intents
Create a payment intent for hosted checkout. Returns a checkout_url to redirect your customer. Authentication: API Key required Request Body
amount
integer
required
Amount in cents
currency
string
required
Currency code (USD, EUR, MAD)
success_url
string
required
URL to redirect after successful paymentMust be HTTPS (except localhost for testing)Supports placeholders: {CHECKOUT_SESSION_ID} will be replaced with payment intent ID
cancel_url
string
URL to redirect if customer cancelsDefault: Same as success_url
order_id
string
Your internal order ID
description
string
Payment description shown to customer
capture_method
string
When to capture fundsValues: automatic (default), manual
  • automatic: Funds captured immediately after authorization
  • manual: You must manually capture later
customer_email
string
Customer email (pre-filled on checkout page)
metadata
object
Custom metadata
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payment-intents \
  -H "X-API-Key: pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 9999,
    "currency": "USD",
    "success_url": "https://yourstore.com/order/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yourstore.com/order/cancel",
    "description": "Order #12345 - Premium Plan",
    "customer_email": "[email protected]",
    "metadata": {
      "order_id": "12345"
    }
  }'
Response (201 Created)
{
  "success": true,
  "data": {
    "id": "pi_abc123def456ghi789",
    "client_secret": "pi_abc123def456ghi789_secret_xyz789uvw456rst123",
    "checkout_url": "https://checkout-page-amber.vercel.app/checkout/pi_abc123def456ghi789?client_secret=pi_abc123def456ghi789_secret_xyz789uvw456rst123",
    "amount": 9999,
    "currency": "USD",
    "status": "created",
    "success_url": "https://yourstore.com/order/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yourstore.com/order/cancel",
    "description": "Order #12345 - Premium Plan",
    "expires_at": "2026-01-24T11:00:00Z",
    "created_at": "2026-01-24T10:00:00Z"
  }
}
Next Steps:
  1. Redirect your customer to checkout_url
  2. Customer completes payment on hosted page
  3. Customer is redirected to your success_url with ?payment_intent=pi_abc123...
  4. Verify payment status on your server

Get Payment Intent (Public)

GET
endpoint
/api/public/payment-intents/:id
Get payment intent details (browser-safe, no sensitive data returned). Authentication: None required (public endpoint) Path Parameters
id
string
required
Payment intent ID
Example Request
curl -X GET https://paymentgateway.redahaloubi.com/api/public/payment-intents/pi_abc123def456
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pi_abc123def456ghi789",
    "status": "created",
    "amount": 9999,
    "currency": "USD",
    "success_url": "https://yourstore.com/order/success",
    "cancel_url": "https://yourstore.com/order/cancel",
    "expires_at": "2026-01-24T11:00:00Z"
  }
}
Security Note: This endpoint does NOT return client_secret. It only provides public information needed to display the checkout page.

Confirm Payment Intent

POST
endpoint
/api/public/payment-intents/:id/confirm
Confirm a payment intent by submitting card details. This processes the actual payment. Authentication: Client Secret required (in header or query) Path Parameters
id
string
required
Payment intent ID
Headers or Query
X-Client-Secret
string
required
Client secret from payment intent creationAlternative: ?client_secret=pi_abc123_secret_xyz789
Request Body
card
object
required
Card details
customer_email
string
Customer email (optional if provided during intent creation)
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/public/payment-intents/pi_abc123def456/confirm \
  -H "Content-Type: application/json" \
  -H "X-Client-Secret: pi_abc123def456ghi789_secret_xyz789uvw456rst123" \
  -d '{
    "card": {
      "number": "4242424242424242",
      "cardholder_name": "John Doe",
      "exp_month": 12,
      "exp_year": 2027,
      "cvv": "123"
    },
    "customer_email": "[email protected]"
  }'
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "pi_abc123def456ghi789",
    "status": "authorized",
    "payment_id": "pay_xyz789uvw012rst345",
    "redirect_url": "https://yourstore.com/order/success?payment_intent=pi_abc123def456ghi789"
  }
}
401 Unauthorized - Invalid Client Secret
{
  "success": false,
  "error": {
    "code": "INVALID_CLIENT_SECRET",
    "message": "client secret is invalid or expired"
  }
}
410 Gone - Intent Expired
{
  "success": false,
  "error": {
    "code": "INTENT_EXPIRED",
    "message": "payment intent expired (valid for 1 hour)"
  }
}
402 Payment Required - Card Declined
{
  "success": false,
  "error": {
    "code": "PAYMENT_DECLINED",
    "message": "card declined: insufficient funds",
    "remaining_attempts": 3
  }
}
410 Gone - Max Attempts
{
  "success": false,
  "error": {
    "code": "MAX_ATTEMPTS_REACHED",
    "message": "maximum payment attempts reached (5)"
  }
}
Payment Attempt Limits:
  • Maximum 5 attempts per payment intent
  • Each failed attempt is tracked
  • After 5 failures, the intent is locked
  • Create a new payment intent for additional attempts

Cancel Payment Intent

POST
endpoint
/api/v1/payment-intents/:id/cancel
Cancel a payment intent before it’s completed. Authentication: API Key required Path Parameters
id
string
required
Payment intent ID to cancel
Example Request
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payment-intents/pi_abc123def456/cancel \
  -H "X-API-Key: pk_live_your_api_key"
Response (200 OK)
{
  "success": true,
  "message": "payment intent canceled"
}
400 Bad Request - Already Completed
{
  "success": false,
  "error": "cannot cancel completed payment intent"
}

Transaction Endpoints

Get Transaction

GET
endpoint
/api/v1/transactions/:id
Get details of a specific transaction. Authentication: API Key required Path Parameters
id
string
required
Transaction ID
Example Request
curl -X GET https://paymentgateway.redahaloubi.com/api/v1/transactions/txn_abc123def456 \
  -H "X-API-Key: pk_live_your_api_key"
Response (200 OK)
{
  "success": true,
  "data": {
    "id": "txn_abc123def456ghi789",
    "payment_id": "pay_xyz789uvw012rst345",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "response_code": "00",
    "response_message": "Approved",
    "created_at": "2026-01-24T10:00:00Z"
  }
}

List Transactions

GET
endpoint
/api/v1/transactions
List all transactions for your merchant account. Authentication: API Key required Query Parameters
status
string
Filter by statusValues: authorized, captured, voided, refunded, failed
limit
integer
Number of results per pageDefault: 10Max: 100
offset
integer
Number of results to skipDefault: 0
Example Request
curl -X GET "https://paymentgateway.redahaloubi.com/api/v1/transactions?status=authorized&limit=20&offset=0" \
  -H "X-API-Key: pk_live_your_api_key"
Response (200 OK)
{
  "success": true,
  "data": {
    "transactions": [
      {
        "id": "txn_abc123def456",
        "payment_id": "pay_xyz789uvw012",
        "status": "authorized",
        "amount": 9999,
        "currency": "USD",
        "created_at": "2026-01-24T10:00:00Z"
      },
      {
        "id": "txn_def456ghi789",
        "payment_id": "pay_rst345mno678",
        "status": "authorized",
        "amount": 4999,
        "currency": "EUR",
        "created_at": "2026-01-24T09:30:00Z"
      }
    ],
    "total": 47,
    "limit": 20,
    "offset": 0
  }
}

Test Cards

Use these test card numbers for development and testing:

βœ… Visa - Approved

Card Number: 4242 4242 4242 4242Expiry: Any future date (e.g., 12/2027)CVV: Any 3 digits (e.g., 123)Result: Authorization approved

βœ… Mastercard - Approved

Card Number: 5555 5555 5555 4444Expiry: Any future dateCVV: Any 3 digitsResult: Authorization approved

❌ Generic Decline

Card Number: 4000 0000 0000 0002Expiry: Any future dateCVV: Any 3 digitsResult: Declined (code 05 - Do not honor)

❌ Insufficient Funds

Card Number: 4000 0000 0000 9995Expiry: Any future dateCVV: Any 3 digitsResult: Declined (code 51)

❌ Expired Card

Card Number: 4000 0000 0000 0069Expiry: Any future dateCVV: Any 3 digitsResult: Declined (code 54)

❌ CVV Mismatch

Card Number: 4000 0000 0000 0127Expiry: Any future dateCVV: Any 3 digitsResult: Declined (code N7)

❌ Processing Error

Card Number: 4000 0000 0000 0119Expiry: Any future dateCVV: Any 3 digitsResult: Declined (code 96)

⚠️ High Fraud Risk

Card Number: 4000 0000 0000 0259Expiry: Any future dateCVV: Any 3 digitsResult: Declined (fraud score > 70)
Test Card Rules:
  • All test cards use the same validation rules as real cards
  • Use any valid future expiry date (e.g., 12/2027)
  • Use any 3-digit CVV (except for CVV mismatch test)
  • Cardholder name can be anything
  • No real money is charged

Payment Status Lifecycle

Status Descriptions

Payment Intent StatusPayment intent created but no payment attempt yet.Next actions: Confirm payment intent, Cancel
Funds held on customer’s cardAuthorization is valid for 7 days. No money has been charged yet.Next actions: Capture, Void
Payment completedFunds have been charged to the customer’s card.Next actions: Refund
Authorization canceledHold released on customer’s card. No money was charged.Final state - No further actions possible
Fully refundedAll captured funds returned to customer.Final state - No further actions possible
Partially refundedSome funds returned to customer, remaining amount still captured.Next actions: Additional refunds (up to remaining amount)
Payment failedAuthorization attempt declined by issuer or fraud system.Final state - Create new payment for retry
Authorization expiredAuthorization not captured within 7 days. Automatically voided.Final state - Create new payment for retry

Error Codes

400
Bad Request
Invalid request format or validation errorCommon causes:
  • Missing required fields
  • Invalid amount (must be positive integer)
  • Unsupported currency
  • Invalid card format
401
Unauthorized
Authentication failedCommon causes:
  • Missing API key or client secret
  • Invalid API key
  • Expired client secret
  • API key from different merchant
402
Payment Required
Payment declinedCommon causes:
  • Card declined by issuer (insufficient funds, expired, etc.)
  • Fraud risk too high
  • CVV verification failed
  • Card reported lost/stolen
404
Not Found
Resource not foundCommon causes:
  • Invalid payment ID
  • Invalid transaction ID
  • Payment belongs to different merchant
409
Conflict
Request conflicts with current stateCommon causes:
  • Idempotency key already used with different data
  • Payment already captured/voided/refunded
  • Cannot perform action in current status
410
Gone
Resource expired or no longer availableCommon causes:
  • Payment intent expired (1 hour)
  • Authorization expired (7 days)
  • Maximum payment attempts reached
429
Too Many Requests
Rate limit exceededLimits:
  • Payments: 20/sec, 10,000/hour
  • Transactions: 100/sec
  • Public endpoints: 50/sec per IP

Idempotency

Idempotency prevents duplicate payments caused by network retries or accidental double-clicks.

How It Works

1

Include Idempotency Key

Send a unique key in the Idempotency-Key header
-H "Idempotency-Key: order-12345-payment-attempt-1"
2

First Request Processed

The payment is processed normally and response is cached for 24 hours
3

Duplicate Requests Return Cached Response

If the same key is used again within 24 hours with the same request body, the original response is returned immediately without creating a new payment
4

Different Request Body = Error

If the same key is used with a different request body, you’ll get a 409 Conflict error

Best Practices

Use Unique Keys

Include order ID, user ID, timestamp, or attempt numberExample: order-{order_id}-{attempt}

Consistent Keys

Use the same key for all retry attempts of the same payment

24-Hour Expiry

Keys expire after 24 hours. After expiry, a new payment will be created

Test Retries

Test your retry logic in development to ensure proper idempotency handling

Webhooks

Payment API sends webhooks for payment events to keep your server updated in real-time.

Webhook Events

payment.authorized

Payment authorized successfully

payment.captured

Payment captured (charged)

payment.voided

Payment voided (canceled)

payment.refunded

Payment refunded (full or partial)

payment.failed

Payment authorization failed

payment_intent.created

Payment intent created

payment_intent.succeeded

Payment intent completed successfully

payment_intent.canceled

Payment intent canceled

Webhook Payload

{
  "event": "payment.authorized",
  "timestamp": "2026-01-24T10:00:00Z",
  "id": "evt_abc123def456",
  "data": {
    "payment_id": "pay_xyz789uvw012",
    "merchant_id": "merchant_abc123",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "created_at": "2026-01-24T10:00:00Z"
  }
}

Verifying Webhook Signatures

Always verify webhook signatures to ensure requests are from Payment Gateway.
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhooks/payment', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  const event = req.body;
  
  switch(event.event) {
    case 'payment.authorized':
      // Handle authorization
      break;
    case 'payment.captured':
      // Handle capture
      break;
  }
  
  res.status(200).send('OK');
});

Webhook Retry Logic

1

Initial Delivery

Webhook sent immediately after event
2

Retry Schedule

If delivery fails (non-200 response):
  • 1st retry: After 5 minutes
  • 2nd retry: After 15 minutes
  • 3rd retry: After 1 hour
  • 4th retry: After 6 hours
3

Maximum Attempts

After 5 failed attempts, webhook is marked as failed
4

Expiration

Webhooks expire after 24 hours

Next Steps


Questions? Contact support at [email protected]