Skip to main content

Payment Webhook Events

Receive notifications for payment transactions.

Available Events

EventTrigger
payment.succeededPayment successfully processed
payment.failedPayment attempt failed
payment.refundedPayment refunded
payment.partially_refundedPartial refund issued

payment.succeeded

Triggered when payment is successfully processed.

Payload

{
  "id": "evt_abc123",
  "type": "payment.succeeded",
  "created": "2024-01-20T14:30:00Z",
  "data": {
    "id": "pay_xyz789",
    "orderId": "ord_123",
    "customerId": "cust_456",
    "amount": 81.56,
    "currency": "USD",
    "method": "card",
    "last4": "4242",
    "brand": "visa",
    "receiptUrl": "https://receipts.tiquo.co/pay_xyz789",
    "stripePaymentIntentId": "pi_abc123",
    "processedAt": "2024-01-20T14:30:00Z"
  }
}

Data Fields

id
string
Payment ID
orderId
string
Associated order ID
amount
number
Payment amount
currency
string
Currency code (ISO 4217)
method
string
Payment method: card, cash, apple_pay, google_pay
last4
string
Last 4 digits of card
brand
string
Card brand: visa, mastercard, amex
receiptUrl
string
URL to view receipt

Example Handler

case 'payment.succeeded':
  const payment = event.data;
  
  // Update accounting system
  await accounting.recordRevenue({
    amount: payment.amount,
    orderId: payment.orderId,
    paymentId: payment.id,
    date: payment.processedAt
  });
  
  // Send receipt
  await email.send(payment.customerEmail, {
    template: 'receipt',
    receiptUrl: payment.receiptUrl
  });
  break;

payment.failed

Triggered when payment attempt fails.

Payload

{
  "id": "evt_def456",
  "type": "payment.failed",
  "created": "2024-01-20T14:35:00Z",
  "data": {
    "id": "pay_failed789",
    "orderId": "ord_123",
    "customerId": "cust_456",
    "amount": 81.56,
    "currency": "USD",
    "method": "card",
    "last4": "1234",
    "failureCode": "card_declined",
    "failureMessage": "Your card was declined",
    "attemptedAt": "2024-01-20T14:35:00Z"
  }
}

Failure Codes

CodeDescription
card_declinedCard declined by issuer
insufficient_fundsNot enough funds
expired_cardCard has expired
incorrect_cvcWrong CVC entered
processing_errorProcessing error
authentication_required3DS required

Example Handler

case 'payment.failed':
  const failedPayment = event.data;
  
  // Notify customer
  await email.send(failedPayment.customerEmail, {
    template: 'payment_failed',
    reason: failedPayment.failureMessage,
    updatePaymentUrl: `https://app.example.com/orders/${failedPayment.orderId}/payment`
  });
  
  // Alert staff
  await slack.send(`Payment failed for order ${failedPayment.orderId}: ${failedPayment.failureCode}`);
  break;

payment.refunded

Triggered when payment is refunded.

Payload

{
  "id": "evt_ghi789",
  "type": "payment.refunded",
  "created": "2024-01-22T10:00:00Z",
  "data": {
    "id": "ref_abc123",
    "paymentId": "pay_xyz789",
    "orderId": "ord_123",
    "customerId": "cust_456",
    "amount": 81.56,
    "currency": "USD",
    "reason": "Order cancelled",
    "refundedBy": "staff_123",
    "refundedAt": "2024-01-22T10:00:00Z"
  }
}

Example Handler

case 'payment.refunded':
  const refund = event.data;
  
  // Update accounting
  await accounting.recordRefund({
    amount: refund.amount,
    originalPaymentId: refund.paymentId,
    reason: refund.reason
  });
  
  // Notify customer
  await email.send(refund.customerEmail, {
    template: 'refund_processed',
    amount: refund.amount,
    reason: refund.reason
  });
  break;

payment.partially_refunded

Triggered for partial refunds.

Payload

{
  "id": "evt_jkl012",
  "type": "payment.partially_refunded",
  "created": "2024-01-22T11:00:00Z",
  "data": {
    "id": "ref_partial123",
    "paymentId": "pay_xyz789",
    "orderId": "ord_123",
    "originalAmount": 81.56,
    "refundAmount": 25.00,
    "remainingAmount": 56.56,
    "currency": "USD",
    "reason": "Service not provided",
    "refundedAt": "2024-01-22T11:00:00Z"
  }
}

Use Cases

Accounting Integration

Sync with accounting software:
app.post('/webhooks/tiquo', async (req, res) => {
  res.status(200).send('OK');
  
  const event = req.body;
  
  switch (event.type) {
    case 'payment.succeeded':
      await quickbooks.createInvoice(event.data);
      break;
    case 'payment.refunded':
      await quickbooks.createCreditMemo(event.data);
      break;
  }
});

Revenue Tracking

Track revenue metrics:
case 'payment.succeeded':
  analytics.track('Payment Received', {
    amount: payment.amount,
    method: payment.method,
    customerId: payment.customerId
  });
  
  // Update daily revenue
  await redis.incrby(`revenue:${today}`, payment.amount);
  break;

Failed Payment Recovery

Recover failed payments:
case 'payment.failed':
  // Add to retry queue
  await queue.add('retry_payment', {
    orderId: payment.orderId,
    customerId: payment.customerId,
    attempts: 1
  }, { delay: 24 * 60 * 60 * 1000 }); // Retry in 24 hours
  break;