Webhooks
Learn how to receive real-time payment notifications via webhooks
Overview
Webhooks enable your application to receive real-time notifications whenever payment events occur in your account. Instead of polling our API for payment status, webhooks push events directly to your server the moment something happens.
Webhooks are the most reliable way to track payment events. Use them to automatically update your system, trigger fulfillment, or send confirmation emails.
Connect with AI
Give your assistant one message to connect Yolfi and implement verified payment handling. The webhook recipe is optional guidance after connection.
How Webhooks Work
When a payment-related event occurs in our system, we send an HTTP POST request to your configured webhook URL. Your server should respond with a 200 OK status to acknowledge receipt.
Webhook URLs must use public HTTP or HTTPS destinations. Private, loopback, link-local, and other reserved IP addresses are blocked, including addresses returned by DNS. Redirects are not followed; configure the final receiver URL directly. For local development, use a public HTTPS tunnel.
Event Types
Invoice Events
| Event | Description |
|---|---|
invoice.created | Payment initiated, invoice created |
invoice.overdue | Invoice payment deadline passed without payment |
Payment Events
| Event | Description |
|---|---|
payment.confirmed | Payment confirmed with enough confirmations and amount |
Subscription Events
| Event | Description |
|---|---|
subscription.overdue | Subscription renewal deadline passed without payment |
subscription.cancelled | Subscription was cancelled |
Use payment.confirmed as your primary fulfillment trigger. This ensures payment is fully confirmed before you deliver service.
Quick Setup
Set your webhook URL in your organization settings via the API or dashboard.
Use the endpoint-specific signing secret returned when the webhook is created or rotated. Never use the organization API key for signature verification.
Process the webhook payload and respond with 200 OK quickly.
API key and signing secret
The organization API key authorizes webhook management calls. It does not sign deliveries. Creating an endpoint returns a separate endpoint-specific signing secret:
curl -X POST https://app.yolfi.com/api/private/organization/webhook-endpoints \
-H "Authorization: Bearer $YOLFI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production webhook",
"url": "https://merchant.example/webhooks/yolfi",
"adapter": "NONE",
"enabled": true
}'{
"success": true,
"data": {
"id": "WEBHOOK_ENDPOINT_ID",
"signingSecret": "ENDPOINT_SIGNING_SECRET"
}
}Store signingSecret when it is returned. Endpoint list and update responses do not expose it. If it is lost, rotate it with POST /api/private/organization/webhook-endpoints/WEBHOOK_ENDPOINT_ID/rotate-secret and update the receiving service.
Endpoint management API
Use HTTP API authentication for endpoint management:
| Operation | Method and path |
|---|---|
| List endpoints | GET /api/private/organization/webhook-endpoints |
| Create endpoint | POST /api/private/organization/webhook-endpoints |
| Update endpoint | PUT /api/private/organization/webhook-endpoints/{endpointId} |
| Rotate signing secret | POST /api/private/organization/webhook-endpoints/{endpointId}/rotate-secret |
| Remove endpoint | DELETE /api/private/organization/webhook-endpoints/{endpointId} |
Creation accepts these fields; update accepts the same fields as optional changes:
| Field | Type | Required on create | Description |
|---|---|---|---|
name | string | yes | Endpoint label, up to 255 characters. |
url | HTTP(S) URL | yes | Receiver URL, up to 2,048 characters; public-destination restrictions apply. |
adapter | enum | yes | NONE, STRIPE, or LEMON_SQUEEZY. |
enabled | boolean | no | Whether deliveries are enabled. |
metadataFilters | object | no | At most 10 exact-match string filters; keys up to 100 characters, values up to 255. |
List returns { "success": true, "data": [...] }. Create and update return one endpoint in data; create also returns its one-time signingSecret. Rotation returns data.signingSecret. A normal list or update never reveals the existing secret. List and match the receiver URL and adapter before creating another endpoint.
Direct HTTP callers must save the secret into the receiver's secret manager without logging the response. Local CLI/MCP callers store created or rotated secrets in a protected local profile and return a storage acknowledgement; this does not configure a remote deployment automatically. See CLI verification and secret handoff. Rotate an existing secret only deliberately, updating the receiver together.
Test Webhooks
Use Settings -> Webhooks in the dashboard to send a test webhook event to your configured endpoint. Test events use the same delivery path, webhook adapter, and X-Yolfi-Signature header as live events, but their payload contains livemode: false and an evt_test_ event ID.
Test webhooks do not create invoices, payment events, subscriptions, or customer records. They only validate endpoint delivery and payload handling.
Retry Policy
If a delivery fails, we retry with exponential backoff - up to 5 attempts per event:
| Attempt | When |
|---|---|
| 1 | Immediately |
| 2 | ~10 seconds later |
| 3 | ~30 seconds later |
| 4 | ~90 seconds later |
| 5 | ~270 seconds later |
We retry on 5xx responses, 429 Too Many Requests, and connection or timeout errors. After 5 consecutive failures the event is marked failed and enters a 1-hour cooldown, after which delivery is retried again.
Other 4xx responses (for example 400, 401, 403, 404) are treated as permanent failures and are not retried - fix your endpoint or signature verification and send a new event.
Redirect responses and blocked destinations are also permanent failures.
Disabling an endpoint cancels pending deliveries and retries with status FAILED and a cancellation reason. After re-enabling it, the endpoint receives only new events; cancelled deliveries and events from while it was disabled are not replayed. A request already in flight may still arrive.
Delivered and permanently failed history is retained for 30 days after its last update. Pending deliveries and scheduled retries are preserved.
Duplicate deliveries are expected during retries. Your handler should be idempotent and deduplicate by the signed payload id. You may also require X-Yolfi-Event-ID to equal that payload value.
Return 200 OK quickly. Slow responses can time out and count as a failed attempt.
Deadlines
| Scenario | Deadline |
|---|---|
| First payment (one-time or recurring) | 1 hour |
| Recurring cycles (after first payment) | 24 hours |
After an invoice deadline, invoice.overdue is sent for that invoice. For recurring subscriptions, do not treat invoice.overdue as a subscription cancellation by itself; use subscription.overdue or subscription.cancelled for subscription access changes.
Consistent Event Model
All webhook events follow the same structure and include:
- Identifier -
id,invoiceId,orgId - Amount -
amount(final merchant receivable, formatted),amountUsd(USD equivalent) - Pricing context -
currency(source currency),rate(payment-token quote) - Type -
paymentType(ONE_TIMEorRECURRING) - Status - Current state of the invoice/payment
- Customer - Customer info for fulfilling orders