Overview & Event Types
What are webhooks?
Webhooks are server-to-server HTTP callbacks. When something changes in Inflow (a payment is authorized, a subscription is canceled, a withdrawal completes, etc.), we send a POST request to the URL you registered.
Compared to polling GET /api/payment, webhooks:
- Reduce latency — you learn about changes as they happen
- Lower API usage — no repeated status checks
- Carry the same resource payloads you would get from the API (e.g. full payment object)
Deliveries are handled by Svix. Each request is signed; you must verify the signature before trusting the body.
How delivery works
- An event occurs on your account (or on a Connect sub-merchant).
- Inflow sends a message to your Svix application with an event type (e.g.
payment.authorizedorconnect.payment.authorized). - Svix POSTs to your endpoint. The body is often a batch (array under
data). - Your server verifies the signature, returns 2xx within 15 seconds, and processes the event (ideally asynchronously).
Inflow API → Svix → POST https://yourserver.com/webhooks/inflow
Headers: svix-id, svix-timestamp, svix-signatureRegister endpoints with Setting up webhooks. Filter which event types you receive via Managing webhooks.
HTTP body format (Svix Stream)
Every delivery is a JSON object with a data array (batched stream). Each element has eventType (route on this) and payload.
Connect (marketplace) — outer name is prefixed; payment lives inside the wrapper:
{
"data": [
{
"eventType": "connect.payment.authorized",
"payload": {
"object": "connect_event",
"eventType": "payment.authorized",
"subMerchant": { "id": "usr_…", "merchantName": "Seller Alpha" },
"data": { "id": "pay_…", "status": "CHECKOUT_SUCCESS", "…": "…" }
}
}
]
}Direct merchant — no wrapper; payload is the resource (same as the API):
{
"data": [
{
"eventType": "payment.authorized",
"payload": { "id": "pay_…", "status": "CHECKOUT_SUCCESS", "…": "…" }
}
]
}data[].eventType— Svix event name (connect.*for marketplaces, unprefixed for direct merchants). Use this for routing and endpoint filters.data[].payload— Direct: resource body (GET /api/payment/{id}, etc.). Connect:connect_eventwrapper; read the payment (or other resource) frompayload.data.payload.eventType(Connect only) — base name withoutconnect.(e.g.payment.authorized). Convenience duplicate of the inner event; preferdata[].eventTypefor routing.
Always verify using the raw request body and the
svix-*headers. Do not re-serialize JSON before verification.
Direct merchant vs Connect (marketplace)
Inflow has two webhook “namespaces”. Which one you receive depends on who owns the account that registered the webhook and where the activity happened.
| Direct merchant | Connect (marketplace) | |
|---|---|---|
| Who registers the webhook | Direct merchant (INDIVIDUAL) | Marketplace (MARKETPLACE) |
| Event type prefix | None — e.g. payment.settled | connect. — e.g. connect.payment.settled |
| What triggers delivery | Activity on your merchant account | Activity on any of your sub-merchants (fan-out from Connect) |
Default subscription (if you omit eventTypes on create) | All direct event types | All connect.* event types |
| Typical use | Your own checkout, subscriptions, payouts | Platform monitoring sellers you onboarded via Connect |
Direct merchant events
Subscribe to names like payment.created, subscription.active, withdrawal.completed.
The payload is the resource itself (payment, subscription, withdrawal, etc.) — the same JSON shape as the corresponding API.
Connect (marketplace) events
When a sub-merchant (created under your marketplace) has activity, Inflow sends a connect.* event to your marketplace webhook endpoints.
The connect_event object is what you find at data[].payload (not the HTTP root). Structure:
| Field | Meaning |
|---|---|
object | Always connect_event |
eventType | Base event name without the connect. prefix (e.g. payment.authorized) |
subMerchant.id | Sub-merchant user id (usr_…) |
subMerchant.merchantName | Display name, or null if unset |
data | Full resource — same shape as GET /api/payment/{paymentId} when the event is payment-related (status, timeline, products, etc.) |
The outer data[].eventType is the prefixed Svix name (e.g. connect.payment.authorized). That is what you subscribe to on the endpoint and what you should switch on in code.
Sub-merchants do not receive their own webhook fan-out to the marketplace URL. Register webhooks on the marketplace API key and listen for
connect.*only.
Payment status → webhook event (direct & connect)
Internal payment statuses map to dot-notation webhook events:
| Payment status (API / timeline) | Webhook event type |
|---|---|
INITIATION | payment.created |
CHECKOUT_PENDING | payment.pending |
CHECKOUT_SUCCESS | payment.authorized |
PAYMENT_SUCCESS | payment.settled |
PAYMENT_FAILED | payment.failed |
CHECKOUT_CANCELED / CANCELED | payment.canceled |
REFUND_PENDING | payment.refund_pending |
PARTIAL_REFUNDED | payment.partially_refunded |
FULLY_REFUNDED | payment.fully_refunded |
Payment status rows that include DISPUTE_* labels on the payment timeline do not emit dispute.* webhooks. Those events are delivered only from the dispute pipeline (DISPUTE_CREATED → WebhookDisputeDto payload, including evidenceDueAt), with event types mapped from DisputeStatus (OPENED → dispute.opened, UNDER_REVIEW → dispute.under_review, etc.).
For Connect, payment mappings use the connect. prefix (e.g. connect.payment.authorized on CHECKOUT_SUCCESS). Dispute events use connect.dispute.* with the same connect_event wrapper.
Available event types
List direct (unprefixed) event types programmatically:
curl https://api.inflowpay.xyz/api/webhook/event-types \
-H "X-Inflow-Api-Key: inflow_prod_your_key"This endpoint returns SVIX_EVENT_TYPE_DEFINITIONS only — names like payment.settled, not connect.payment.settled. Marketplaces subscribe to connect. + the same base name (e.g. connect.payment.settled). You can pass those names on create and on PATCH /api/webhook/{webhookId}/event-types even though they are not listed by GET /api/webhook/event-types.
Descriptions below match the Svix event-type registry in the API.
Payment
| Event type | Description |
|---|---|
payment.created | A new payment has been created |
payment.pending | Payment is pending (checkout awaiting completion) |
payment.authorized | Payment has been authorized (funds received by provider) |
payment.settled | Payment has been settled (crypto delivered to wallet) |
payment.failed | Payment has failed |
payment.canceled | Payment has been canceled |
payment.expired | Payment has expired without completion (registered in Svix; not emitted by status handlers today) |
payment.refund_pending | A refund is being processed for this payment |
payment.partially_refunded | Payment has been partially refunded |
payment.fully_refunded | Payment has been fully refunded |
Subscription
| Event type | Description |
|---|---|
subscription.created | A new subscription has been created |
subscription.active | Subscription is now active |
subscription.trial_started | Subscription trial period has started |
subscription.past_due | Subscription payment is past due |
subscription.canceled | Subscription has been canceled |
subscription.pending_cancellation | Subscription is pending cancellation at period end |
Deposit (virtual account)
| Event type | Description |
|---|---|
deposit.funds_received | Funds have been received on the virtual account |
deposit.payment_submitted | Deposit payment has been submitted for processing |
deposit.payment_processed | Deposit payment has been processed successfully |
deposit.in_review | Deposit is under review |
deposit.refunded | Deposit has been refunded |
Dispute
| Event type | Description |
|---|---|
dispute.opened | A dispute has been opened on a payment |
dispute.evidence_submitted | Evidence has been submitted for the dispute (registered in Svix; not emitted by dispute handlers today) |
dispute.under_review | Dispute is under review by the payment processor |
dispute.won | Dispute has been resolved in your favor |
dispute.lost | Dispute has been lost |
dispute.accepted | Dispute has been accepted (merchant conceded) |
Withdrawal
| Event type | Description |
|---|---|
withdrawal.initiated | A withdrawal has been initiated |
withdrawal.submitted | Withdrawal has been submitted for processing |
withdrawal.processing | Withdrawal is being processed |
withdrawal.completed | Withdrawal has been completed successfully |
withdrawal.failed | Withdrawal has failed |
withdrawal.canceled | Withdrawal has been canceled |
withdrawal.returned | Withdrawal funds have been returned |
Swap
| Event type | Description |
|---|---|
swap.initiated | A currency swap has been initiated |
swap.pending | Swap is pending (outbound transfer in progress) |
swap.processing | Swap is being processed (cross-chain conversion in progress) |
swap.completed | Swap has been completed successfully |
swap.failed | Swap has failed |
swap.canceled | Swap has been canceled |
swap.refunded | Swap funds have been refunded |
Connect mirrors
Every row above has a Connect counterpart: prefix connect. to the event name.
Examples: connect.payment.settled, connect.subscription.active, connect.withdrawal.completed.
Marketplaces should subscribe only to the connect.* names they care about.
Legacy events (V1 webhooks only)
Older webhook endpoints may still receive legacy snake_case types:
payment_createdpayment_status_updated
New endpoints use V2 dot notation (payment.created, payment.authorized, …). When creating a webhook today, you only receive V2-style types (or their connect.* mirrors for marketplaces).
Subscribing to specific events
On create, pass eventTypes:
curl -X POST https://api.inflowpay.xyz/api/webhook \
-H "X-Inflow-Api-Key: inflow_prod_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourserver.com/webhooks/inflow",
"eventTypes": [
"connect.payment.authorized",
"connect.payment.settled"
]
}'Update later with PATCH /api/webhook/{webhookId}/event-types. The list replaces the full subscription — omit an event type to stop receiving it.
Passing an empty
eventTypesarray subscribes to all events for your account type. See Managing webhooks.
Next steps
- Setting up webhooks — register your URL and secret
- Verifying signatures — required before processing
- Webhook best practices — production checklist
Updated about 1 hour ago