Events
Retrieve and manage webhook events.
Events API
Events represent things that happen in your PayGate account, such as a payment succeeding or a subscription being canceled. When an event occurs, PayGate sends it to your webhook endpoints.
The Event Object
{
"id": "evt_abc123def456",
"object": "event",
"type": "payment.succeeded",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"object": {
"id": "pay_xyz789",
"object": "payment",
"amount": 5000,
"currency": "GHS",
"status": "succeeded",
"payment_method": "mobile_money",
"provider": "mtn",
"phone": "024****567",
...
}
},
"pending_webhooks": 1,
"request": {
"id": "req_abc123",
"idempotency_key": "order_1234"
}
}Attributes
| Attribute | Type | Description |
|---|---|---|
id | string | Unique identifier |
object | string | Always "event" |
type | string | Event type |
created_at | string | When event was created |
data | object | Event data |
data.object | object | The object that triggered the event |
pending_webhooks | integer | Webhooks pending delivery |
request | object | API request that caused this event |
Event Types
Payment Events
| Event | Description |
|---|---|
payment.created | Payment was created |
payment.pending | Payment is pending authorization |
payment.processing | Payment is being processed |
payment.succeeded | Payment completed successfully |
payment.failed | Payment failed |
payment.canceled | Payment was canceled |
Subscription Events
| Event | Description |
|---|---|
subscription.created | Subscription was created |
subscription.updated | Subscription was updated |
subscription.canceled | Subscription was canceled |
subscription.paused | Subscription was paused |
subscription.resumed | Subscription was resumed |
subscription.trial_will_end | Trial ending in 3 days |
subscription.payment_succeeded | Recurring payment succeeded |
subscription.payment_failed | Recurring payment failed |
Payout Events
| Event | Description |
|---|---|
payout.created | Payout was created |
payout.processing | Payout is being processed |
payout.completed | Payout was successful |
payout.failed | Payout failed |
payout.canceled | Payout was canceled |
Refund Events
| Event | Description |
|---|---|
refund.created | Refund was created |
refund.succeeded | Refund was successful |
refund.failed | Refund failed |
Checkout Events
| Event | Description |
|---|---|
checkout.session.completed | Checkout session completed |
checkout.session.expired | Checkout session expired |
Customer Events
| Event | Description |
|---|---|
customer.created | Customer was created |
customer.updated | Customer was updated |
customer.deleted | Customer was deleted |
Retrieve an Event
Retrieves an event by ID.
GET /v1/events/:idcurl https://api.44.200.142.19.nip.io/v1/events/evt_abc123def456 \
-H "Authorization: Bearer sk_test_..."const event = await paygate.events.retrieve('evt_abc123def456')
console.log(event.type) // 'payment.succeeded'
console.log(event.data.object.id) // 'pay_xyz789'event = client.events.retrieve('evt_abc123def456')
print(event.type) # 'payment.succeeded'
print(event.data.object.id) # 'pay_xyz789'List Events
Returns a list of events.
GET /v1/eventsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | Number of results (1-100) |
starting_after | string | Cursor for pagination |
ending_before | string | Cursor for pagination |
type | string | Filter by event type |
created[gte] | string | Filter by creation date |
created[lte] | string | Filter by creation date |
curl "https://api.44.200.142.19.nip.io/v1/events?type=payment.succeeded&limit=10" \
-H "Authorization: Bearer sk_test_..."const events = await paygate.events.list({
type: 'payment.succeeded',
limit: 10
})
for (const event of events.data) {
console.log(event.id, event.type)
}events = client.events.list(type='payment.succeeded', limit=10)
for event in events.data:
print(event.id, event.type)Response
{
"object": "list",
"data": [
{
"id": "evt_abc123def456",
"object": "event",
"type": "payment.succeeded",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"object": {...}
}
}
],
"has_more": true,
"url": "/v1/events"
}Handling Events
Events are delivered to your webhook endpoints. Here's how to handle them:
import express from 'express'
import { Webhook } from '@paygate/node'
const app = express()
const endpointSecret = 'whsec_...'
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-paygate-signature']
let event
try {
event = Webhook.constructEvent(req.body, signature, endpointSecret)
} catch (err) {
console.error('Webhook signature verification failed:', err.message)
return res.status(400).send('Invalid signature')
}
// Handle the event
switch (event.type) {
case 'payment.succeeded':
const payment = event.data.object
await handlePaymentSuccess(payment)
break
case 'payment.failed':
const failedPayment = event.data.object
await handlePaymentFailure(failedPayment)
break
case 'subscription.created':
const subscription = event.data.object
await handleNewSubscription(subscription)
break
case 'subscription.canceled':
const canceledSub = event.data.object
await handleCanceledSubscription(canceledSub)
break
default:
console.log(`Unhandled event type: ${event.type}`)
}
res.json({ received: true })
})Best Practices
1. Handle Events Idempotently
Events may be delivered more than once. Use the event ID to avoid processing duplicates:
async function handleEvent(event) {
// Check if already processed
if (await isEventProcessed(event.id)) {
return
}
// Process the event
await processEvent(event)
// Mark as processed
await markEventProcessed(event.id)
}2. Return 200 Quickly
Acknowledge webhooks quickly, then process asynchronously:
app.post('/webhooks', (req, res) => {
// Verify signature
const event = Webhook.constructEvent(...)
// Acknowledge immediately
res.json({ received: true })
// Process async
queueEventForProcessing(event)
})3. Use Event Types Effectively
Listen only for events you care about:
// When creating webhook endpoint
const endpoint = await paygate.webhooks.endpoints.create({
url: 'https://yoursite.com/webhooks',
events: [
'payment.succeeded',
'payment.failed',
'subscription.created',
'subscription.canceled'
]
})You can also use * to receive all events, but this isn't recommended for production.
Retry Events
If you need to reprocess an event, you can fetch it from the API:
// Fetch a specific event
const event = await paygate.events.retrieve('evt_abc123def456')
// Reprocess it
await handleEvent(event)Or fetch recent events of a specific type:
// Get all payment.succeeded events from the last hour
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000)
const events = await paygate.events.list({
type: 'payment.succeeded',
created: { gte: oneHourAgo.toISOString() }
})
for (const event of events.data) {
await handleEvent(event)
}