Skip to main content
Kyren Pay sends webhook notifications for the following event types.

Event Types

EventDescriptionTrigger
order.paidA payment has been confirmedCustomer completes checkout
checkout.completedA checkout session has been completedPayment successfully processed
checkout.expiredA checkout session has expired30 minutes without payment
order.refundedAn order has been refundedAdmin processes a refund
payout.completedA payout has been processedFunds transferred to merchant
payout.failedA payout has failedTransfer failed
kyc.approvedKYC verification approvedAdmin approves KYC
kyc.rejectedKYC verification rejectedAdmin rejects KYC

Event Object Structure

All webhook events share the same top-level structure:
{
  "id": "evt_abc123",
  "type": "order.paid",
  "created_at": "2026-01-15T10:35:00Z",
  "data": {
    // Event-specific data
  }
}
FieldTypeDescription
idstringUnique event identifier (use for deduplication)
typestringThe event type
created_atstringISO 8601 timestamp
dataobjectEvent-specific payload

order.paid

Sent when a customer successfully completes a payment.
{
  "id": "evt_abc123",
  "type": "order.paid",
  "created_at": "2026-01-15T10:35:00Z",
  "data": {
    "order_id": "order_def456",
    "product_id": "prod_abc123",
    "customer_email": "customer@example.com",
    "amount": 9.99,
    "currency": "USD",
    "net_amount": 9.29,
    "paid_at": "2026-01-15T10:35:00Z"
  }
}
FieldTypeDescription
order_idstringThe order ID
product_idstringThe product that was purchased
customer_emailstringCustomer’s email address
amountnumberTotal payment amount
currencystringThree-letter currency code
net_amountnumberAmount after fees
paid_atstringWhen the payment was confirmed
This is the most important event. Use it to fulfill orders — for example, adding credits to a user’s account.

checkout.completed

Sent when a checkout session is completed successfully. Contains the same data as order.paid.

checkout.expired

Sent when a checkout session expires without payment (after 30 minutes).
{
  "id": "evt_ghi789",
  "type": "checkout.expired",
  "created_at": "2026-01-15T11:00:00Z",
  "data": {
    "checkout_id": "cs_xyz789",
    "product_id": "prod_abc123",
    "expired_at": "2026-01-15T11:00:00Z"
  }
}

order.refunded

Sent when an order is refunded by the platform.
{
  "id": "evt_jkl012",
  "type": "order.refunded",
  "created_at": "2026-01-16T14:00:00Z",
  "data": {
    "order_id": "order_def456",
    "product_id": "prod_abc123",
    "amount": 9.99,
    "currency": "USD",
    "refunded_at": "2026-01-16T14:00:00Z"
  }
}

payout.completed

Sent when a payout to your bank account is successfully processed.
{
  "id": "evt_mno345",
  "type": "payout.completed",
  "created_at": "2026-01-20T09:00:00Z",
  "data": {
    "payout_id": "po_abc123",
    "amount": 500.00,
    "currency": "USD",
    "completed_at": "2026-01-20T09:00:00Z"
  }
}

payout.failed

Sent when a payout fails.
{
  "id": "evt_pqr678",
  "type": "payout.failed",
  "created_at": "2026-01-20T09:00:00Z",
  "data": {
    "payout_id": "po_abc123",
    "amount": 500.00,
    "currency": "USD",
    "reason": "Invalid bank account details"
  }
}

Handling Events

Here’s how to handle different event types in your webhook endpoint:
app.post('/webhooks/kyren', (req, res) => {
  // ... verify signature first ...

  const event = JSON.parse(req.body.toString());

  switch (event.type) {
    case 'order.paid':
      handleOrderPaid(event.data);
      break;
    case 'order.refunded':
      handleOrderRefunded(event.data);
      break;
    case 'checkout.expired':
      handleCheckoutExpired(event.data);
      break;
    default:
      console.log(`Unhandled event: ${event.type}`);
  }

  res.status(200).send('OK');
});