Skip to main content

Webhooks

Webhooks allow your application to receive real-time notifications when events happen in your Gale account, such as completed payments, failed charges, or subscription changes.

How Webhooks Work

  1. Customer completes payment on Gale’s checkout page
  2. Gale processes the payment
  3. Gale sends a POST request to your webhook endpoint with event data
  4. Your server processes the event (e.g., fulfills order, sends email)
  5. Your server returns a 200 OK response
  6. Event is marked as delivered successfully
If your server doesn’t respond with 200, Gale will retry the webhook with exponential backoff.

Setup

1. Create Webhook Endpoint

Create an endpoint on your server to receive webhook events:
app.post('/webhooks/gale', async (req, res) => {
  const event = req.body;

  // Process the event
  switch (event.type) {
    case 'payment_link.paid':
      await handlePaymentSuccess(event.data);
      break;
    case 'order.created':
      await handleOrderCreated(event.data);
      break;
    // ... handle other event types
  }

  // Return 200 to acknowledge receipt
  res.status(200).send('OK');
});

2. Configure in Dashboard

  1. Log in to Gale Dashboard
  2. Go to SettingsWebhooks
  3. Click Add Endpoint
  4. Enter your webhook URL
  5. Select events to receive
  6. Click Create

Understanding Webhooks & Orders

All payment methods (checkout sessions, payment links, subscriptions) create orders when paid. This means:
  • Checkout session paid → order.created fires
  • Payment link paid → payment_link.paid fires, then order.created fires
  • Subscription payment → subscription.payment_succeeded fires, then order.created fires
The order object is your source of truth for all successful payments, regardless of how the customer paid. For most integrations, listen to order.created to fulfill purchases.

Webhook Events

EventDescription
payment_link.createdPayment link created
payment_link.paidPayment successfully completed
payment_link.expiredPayment link expired without payment
payment_link.cancelledPayment link cancelled

Order Events

EventDescription
order.createdOrder created from paid payment link
order.completedOrder completed successfully
order.failedOrder payment failed
order.refundedOrder was refunded

Subscription Events

EventDescription
subscription.createdSubscription created
subscription.updatedSubscription updated
subscription.trial_endingTrial period ending soon (3 days before)
subscription.trial_endedTrial period ended
subscription.payment_succeededRecurring payment succeeded
subscription.payment_failedRecurring payment failed
subscription.cancelledSubscription cancelled
subscription.endedSubscription ended

Product Events

EventDescription
product.createdProduct created
product.updatedProduct updated
product.deletedProduct deleted

Refund Events

EventDescription
refund.createdRefund initiated
refund.succeededRefund processed successfully
refund.failedRefund failed

Event Examples

{
  "id": "evt_abc123xyz",
  "type": "payment_link.paid",
  "created_at": "2025-10-18T15:30:00Z",
  "data": {
    "id": "plink_abc123",
    "amount_cents": 4995,
    "customer": {
      "email": "customer@example.com"
    },
    "order": {
      "id": "ord_xyz789"
    }
  }
}

order.created

{
  "id": "evt_def456xyz",
  "type": "order.created",
  "created_at": "2025-10-18T15:30:00Z",
  "data": {
    "id": "ord_xyz789",
    "order_number": "ORD-2025-001234",
    "status": "completed",
    "customer": {
      "email": "customer@example.com"
    }
  }
}

Best Practices

  • Return 200 quickly, process asynchronously
  • Handle duplicate events using event IDs
  • Verify webhook signatures
  • Handle all event types with a default case