Webhook Event Reference
Complete reference for all EdenPay webhook events and their payload structures.
Event Structure
All webhook events follow this common structure:
{
"id": "evt_abc123",
"type": "payment.confirmed",
"createdAt": "2025-01-15T10:30:00Z",
"data": {
// Event-specific data
}
}
Field | Type | Description |
---|---|---|
id | string | Unique identifier for this event |
type | string | Event type (see below for all types) |
createdAt | string | ISO 8601 timestamp when event was created |
data | object | Event-specific payload |
Payment Events
payment.created
Triggered when a new payment is initiated.
Use case: Track payment creation, start monitoring, or update UI status.
{
"id": "evt_abc123",
"type": "payment.created",
"createdAt": "2025-01-15T10:30:00Z",
"data": {
"paymentId": "pay_xyz789",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"status": "pending",
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"workspaceId": "ws_abc123",
"metadata": {
"orderId": "order_123",
"customerId": "cust_456"
}
}
}
payment.pending
Triggered when a payment transaction is detected on the blockchain but not yet confirmed.
Use case: Show "Payment detected, awaiting confirmation" status to customers.
{
"id": "evt_def456",
"type": "payment.pending",
"createdAt": "2025-01-15T10:31:00Z",
"data": {
"paymentId": "pay_xyz789",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"status": "pending",
"txHash": "0x1234567890abcdef...",
"confirmationsReceived": 1,
"confirmationsRequired": 12,
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"workspaceId": "ws_abc123",
"metadata": {
"orderId": "order_123",
"customerId": "cust_456"
}
}
}
payment.confirmed ⭐
This is the most important event. Triggered when a payment has received sufficient blockchain confirmations and is considered final.
Use case: Fulfill orders, credit accounts, grant access, or trigger any business logic that requires payment confirmation.
This is the event you should use to fulfill orders and grant access to paid content. The payment is irreversible at this point.
{
"id": "evt_ghi789",
"type": "payment.confirmed",
"createdAt": "2025-01-15T10:35:00Z",
"data": {
"paymentId": "pay_xyz789",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"status": "confirmed",
"txHash": "0x1234567890abcdef...",
"confirmationsReceived": 12,
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"workspaceId": "ws_abc123",
"confirmedAt": "2025-01-15T10:35:00Z",
"metadata": {
"orderId": "order_123",
"customerId": "cust_456"
}
}
}
Confirmation Requirements by Network:
- Ethereum: 12 confirmations (~2.5 minutes)
- Polygon: 100 confirmations (~3.5 minutes)
- Base/Optimism: 12 confirmations (~30 seconds)
- Arbitrum: 12 confirmations (~20 seconds)
- Sui: 1 confirmation (~2 seconds)
- Aptos: 1 confirmation (~4 seconds)
payment.failed
Triggered when a payment fails or expires.
Use case: Cancel orders, notify customers, or clean up pending transactions.
{
"id": "evt_jkl012",
"type": "payment.failed",
"createdAt": "2025-01-15T11:00:00Z",
"data": {
"paymentId": "pay_xyz789",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"status": "failed",
"failureReason": "Payment expired after 30 minutes",
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"workspaceId": "ws_abc123",
"metadata": {
"orderId": "order_123",
"customerId": "cust_456"
}
}
}
Common Failure Reasons:
Payment expired after 30 minutes
- Customer didn't complete payment in timeInsufficient amount received
- Customer sent less than requiredWrong network
- Customer sent to wrong blockchainTransaction reverted
- Blockchain transaction failed
payment.refunded
Triggered when a payment is refunded to the customer.
Use case: Revoke access, update accounting, or notify customer of refund.
{
"id": "evt_mno345",
"type": "payment.refunded",
"createdAt": "2025-01-15T12:00:00Z",
"data": {
"paymentId": "pay_xyz789",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"status": "refunded",
"refundTxHash": "0xabcdef1234567890...",
"refundReason": "Customer requested refund",
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"workspaceId": "ws_abc123",
"refundedAt": "2025-01-15T12:00:00Z",
"metadata": {
"orderId": "order_123",
"customerId": "cust_456"
}
}
}
Checkout Session Events
checkout.session.created
Triggered when a new checkout session is created.
Use case: Track checkout funnel, monitor conversion rates.
{
"id": "evt_pqr678",
"type": "checkout.session.created",
"createdAt": "2025-01-15T10:29:00Z",
"data": {
"sessionId": "cs_abc123",
"status": "pending",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"productId": "prod_xyz789",
"workspaceId": "ws_abc123",
"checkoutUrl": "https://checkout.blockeden.xyz/cs_abc123",
"expiresAt": "2025-01-15T11:00:00Z",
"metadata": {
"orderId": "order_123"
}
}
}
checkout.session.completed
Triggered when a checkout session is successfully completed (payment confirmed).
Use case: Track successful checkouts, conversion analytics.
{
"id": "evt_stu901",
"type": "checkout.session.completed",
"createdAt": "2025-01-15T10:35:00Z",
"data": {
"sessionId": "cs_abc123",
"status": "completed",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"productId": "prod_xyz789",
"paymentId": "pay_xyz789",
"workspaceId": "ws_abc123",
"completedAt": "2025-01-15T10:35:00Z",
"metadata": {
"orderId": "order_123"
}
}
}
checkout.session.expired
Triggered when a checkout session expires without payment.
Use case: Track abandoned checkouts, send recovery emails.
{
"id": "evt_vwx234",
"type": "checkout.session.expired",
"createdAt": "2025-01-15T11:00:00Z",
"data": {
"sessionId": "cs_abc123",
"status": "expired",
"amount": "100.00",
"currency": "USDC",
"network": "ethereum",
"productId": "prod_xyz789",
"workspaceId": "ws_abc123",
"expiredAt": "2025-01-15T11:00:00Z",
"metadata": {
"orderId": "order_123"
}
}
}
Event Lifecycle
A typical payment flow produces events in this order:
Alternative flows:
- Payment expires:
payment.failed
→checkout.session.expired
- Payment refunded:
payment.refunded
(after successful payment)
Event Handling Best Practices
1. Handle Events Idempotently
Always check if you've already processed an event:
async function handleWebhook(event) {
// Check if already processed
const existing = await db.webhookEvents.findOne({
eventId: event.id
});
if (existing) {
console.log('Event already processed:', event.id);
return; // Skip duplicate
}
// Process the event
await processPayment(event.data);
// Mark as processed
await db.webhookEvents.create({
eventId: event.id,
type: event.type,
processedAt: new Date()
});
}
2. Use Metadata for Context
Pass your system's IDs through metadata:
// When creating a payment
const payment = await createPayment({
amount: '100.00',
currency: 'USDC',
metadata: {
orderId: 'order_123',
customerId: 'cust_456',
productSku: 'PROD-001'
}
});
// In your webhook handler
function handlePaymentConfirmed(data) {
const { orderId, customerId, productSku } = data.metadata;
await fulfillOrder(orderId, customerId, productSku);
}
3. Return 200 Quickly
Acknowledge receipt immediately, process asynchronously:
app.post('/webhooks', async (req, res) => {
// Verify signature first
if (!verifySignature(req)) {
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(req.body.toString());
// Return 200 immediately
res.status(200).json({ received: true });
// Process asynchronously
processEventAsync(event).catch(err => {
console.error('Error processing event:', err);
// Log to error tracking service
});
});
4. Handle Unknown Event Types
Be defensive - new event types may be added:
switch (event.type) {
case 'payment.confirmed':
await handlePaymentConfirmed(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
default:
// Log but don't fail
console.log('Unknown event type:', event.type);
// Still return 200 to acknowledge receipt
}
Recommended Event Subscriptions
Choose based on your use case:
Minimal Setup (E-commerce)
- ✅
payment.confirmed
- Fulfill orders
Recommended Setup
- ✅
payment.confirmed
- Fulfill orders - ✅
payment.failed
- Cancel orders and notify customers - ✅
checkout.session.expired
- Track abandoned carts
Full Analytics Setup
- ✅
checkout.session.created
- Track checkout starts - ✅
payment.created
- Track payment attempts - ✅
payment.pending
- Update UI with progress - ✅
payment.confirmed
- Fulfill orders - ✅
payment.failed
- Handle failures - ✅
payment.refunded
- Process refunds - ✅
checkout.session.completed
- Track conversions - ✅
checkout.session.expired
- Track abandonment
Testing Events
Test your webhook handler using the dashboard:
- Navigate to Accept Payments → Webhooks
- Click Test button on your endpoint
- A
webhook.test.event
will be sent - Check your server logs to verify receipt and processing
Common Payload Fields
Field | Type | Always Present | Description |
---|---|---|---|
paymentId | string | Payment events | Unique payment identifier |
sessionId | string | Checkout events | Unique checkout session identifier |
amount | string | Yes | Payment amount (decimal string) |
currency | string | Yes | Currency code (USDC, USDT, ETH, etc.) |
network | string | Yes | Blockchain network |
status | string | Yes | Current status |
workspaceId | string | Yes | Your workspace identifier |
metadata | object | Yes | Custom data you provided |
txHash | string | When available | Blockchain transaction hash |
recipientAddress | string | Payment events | Receiving wallet address |
Next Steps
- 🔒 Security: Read the Signature Verification Guide
- 🚀 Get Started: Follow the Quick Start Guide
- 🛠️ Debug: Check the Troubleshooting Guide
Need Help?
- Dashboard: View delivery attempts and debug events
- Forum: https://blockeden.xyz/forum
- Support: support@blockeden.xyz