Webhooks
Real-time notifications for payment events and system alerts.
Webhooks allow your application to receive real-time notifications when events occur in StableOps, such as when a payment is detected, confirmed, or finalized.
Overview
Instead of polling the API to check payment status, StableOps sends HTTP POST requests to your server when events happen. This enables:
- Real-time updates: Know immediately when payments arrive
- Reduced API calls: No need to poll for status changes
- Reliable delivery: Automatic retries with exponential backoff
- Event history: All webhook deliveries are logged and can be replayed
How Webhooks Work
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Blockchain │────────▶│ StableOps │────────▶│ Your App │
└─────────────┘ └─────────────┘ └─────────────┘
Payment sent Event detected Webhook sent- An event occurs (e.g., payment detected on blockchain)
- StableOps creates a webhook delivery
- HTTP POST request is sent to your endpoint
- Your server processes the event and returns 200 OK
- If delivery fails, StableOps retries with exponential backoff
Webhook Events
Payment Events
payment_order.created
Sent when a new payment order is created.
{
"type": "payment_order.created",
"data": {
"id": "po_abc123",
"merchant_order_id": "order_123",
"scenario": "checkout",
"amount": "10.00",
"settlement_asset": "USDC",
"status": "created",
"expires_at": "2024-01-01T12:30:00Z",
"metadata": {
"user_id": "user_456"
},
"created_at": "2024-01-01T12:00:00Z",
"accepted_assets": [
{ "chain": "base", "asset": "USDC" }
],
"payment_instructions": [
{ "chain": "base", "asset": "USDC", "address": "0x1234..." }
]
}
}payment.detected
Sent when a payment transaction is first seen on the blockchain (0 confirmations).
Action: Update UI to show "Payment received, confirming..."
Warning: Do not fulfill the order yet - the transaction could still be reverted.
payment.finalized
Sent when the payment has reached finality and cannot be reverted.
Action: Safe to fulfill the order - payment is guaranteed.
This is the recommended event to trigger order fulfillment.
Setting Up Webhooks
1. Create an Endpoint
In your StableOps dashboard:
- Go to Developers → Webhooks
- Click Add Endpoint
- Enter your webhook URL (must be HTTPS in production)
- Select which events to receive (omit
enabled_eventson create to subscribe to everything) - Save the webhook secret
The secret field is returned only on create and rotate — store it
somewhere durable; the dashboard will not show it again. After you call
rotate-secret, the previous secret stays valid alongside the new one for
24 hours, so you can roll out the new value without dropping deliveries.
2. Verify Signatures
Always verify webhook signatures to ensure requests are from StableOps.
import { SIGNATURE_HEADER, verifySignature } from '@stableops/api-sdk/webhooks'
const result = verifySignature({
secrets: [webhookSecret],
header: request.headers.get(SIGNATURE_HEADER) ?? undefined,
rawBody,
})
if (!result.ok) {
console.error('Invalid signature:', result.reason)
// Reject the request
}Delivery, retries, and the dead letter queue
Success criteria
Any 2xx response is treated as success. Any other status code, a network
error, or no response within 10 seconds counts as failure.
Retry schedule
Failed deliveries are rescheduled on this curve before moving to the dead letter queue on attempt 6:
| Attempt | Delay |
|---|---|
| 1 | 30 s |
| 2 | 60 s |
| 3 | 5 min |
| 4 | 30 min |
| 5 | 2 h |
| 6+ | DLQ |
Delivery log fields
Key fields you'll see on webhook-deliveries:
| Field | Description |
|---|---|
attempts | Number of HTTP attempts performed |
response_status | Downstream status code on the most recent attempt |
response_duration_ms | How long the last attempt took |
error_message | Short, log-friendly reason for the most recent failure |
next_retry_at | When the worker will retry — null once delivery is terminal |
status | pending, succeeded, failed, dead_letter |
Replay
The three replay endpoints (endpoint replay, single-delivery replay, and replay-dead-letters) all enqueue a brand-new delivery row — the original audit log is preserved. The dashboard's "replay" button is just these endpoints under the hood.
Best Practices
1. Always Verify Signatures
2. Return 200 Quickly
3. Process Idempotently
4. Use Raw Body for Verification
5. Handle All Event Types
6. Log Everything
7. Monitor Delivery Health
Next Steps
- Payment Orders - Understanding payment orders
- Integration Guides - Framework-specific examples