Webhooks
Events
Catalog of TuCapi Business webhook events and the data each one carries.
Catalog
| Event | When |
|---|---|
order.created | Your customer picked a payment method and a pending order was created. |
order.paid | The payment was confirmed and the net amount credited to your balance. |
order.expired | The order expired without being paid. |
payout.created | You requested a payout. |
payout.completed | The payout was confirmed on-chain. |
payout.failed | The payout failed and the balance was returned. |
subscription.* | Recurring billing: created, installment generated, paid or overdue, paused, resumed, cancelled and ended. See below. |
webhook.test | Manual test from the dashboard. You can't subscribe to it. |
Order events
| Event | data fields |
|---|---|
order.created | orderId, merchantOrderRef, amount, currency, paymentMethod, status, paymentLinkId (charge id), expiresAt, createdAt, source, store (store sales only) |
order.paid | orderId, merchantOrderRef, amount, currency, paymentMethod, netUsdt, externalRef, customerEmail, paidAt, source, store (store sales only), meta (optional, depends on the method) |
order.expired | orderId, merchantOrderRef, amount, currency, paymentMethod, paymentLinkId, expiresAt, hadRailAssignment |
Values don't use the API's format
paymentMethod is uppercase: PAYPAL, ZELLE, STRIPE (card) or, for peso payments, BRIDGE_COP and BRIDGE_MXN. The status in order.created is PENDING. And amount doesn't always have two decimals.order.expired also covers orders that failed to start the payment (hadRailAssignment: false).
{ "id": "evt_2b1c9d0e4f5a4a6b8c7d9e0f1a2b3c4d", "type": "order.paid", "createdAt": "2026-09-15T18:50:31Z", "merchantId": "3e630ae9-6ee0-4ee7-b40c-1ea853829377", "data": { "orderId": "c9227f9b-13f4-4e9c-8fe0-4644e62b83cd", "merchantOrderRef": "MO-k7x2m9qz-1a2b3c4d", "amount": "125.00", "currency": "USD", "paymentMethod": "PAYPAL", "netUsdt": "120.33", "externalRef": "5O190127TN364715T", "customerEmail": "ana@example.com", "paidAt": "2026-09-15T18:50:31Z", "source": "payment_link" }}Where the order came from
order.created and order.paid carry source, which says where the order came from:
source | The order came from |
|---|---|
payment_link | A payment link you made in the dashboard. |
invoice | An invoice. |
store | A sale from your store. Carries store, below. |
subscription | A recurring payment installment. |
api | A charge created with the API (POST /v1/charges). |
manual | Added by the TuCapi team, for example a deposit assigned by hand. |
If you get a value you don't know, treat it as payment_link: the list may grow.
Store sales
When source is store, you also get store with the order:
| Field | What it is |
|---|---|
orderId | The store order id (not the payment order id). |
number | The order number, as you see it in Orders. It's null in order.created: it's assigned when paid. |
items | The products: productId, variantId and variant (the chosen size or color, null if the product has none), name, quantity, unitPrice and lineTotal. productId is null if you deleted the product. |
subtotal, discount, deliveryFee, total | The order amounts, as text with two decimals. |
couponCode | The coupon used, or null. |
deliveryMethod | PICKUP (pickup), DELIVERY (home delivery) or SHIPPING (nationwide shipping). |
customer | name, phone, address and note. Address and note may be null. |
{ "id": "evt_7c3d1e2f4a5b4c6d8e9f0a1b2c3d4e5f", "type": "order.paid", "createdAt": "2026-10-27T15:12:09Z", "merchantId": "3e630ae9-6ee0-4ee7-b40c-1ea853829377", "data": { "orderId": "c9227f9b-13f4-4e9c-8fe0-4644e62b83cd", "merchantOrderRef": "MO-t4n8p2wd-9f8e7d6c", "amount": "32.00", "currency": "USD", "paymentMethod": "STRIPE", "netUsdt": "29.76", "externalRef": "pi_3Q…", "customerEmail": "ana@example.com", "paidAt": "2026-10-27T15:12:09Z", "source": "store", "store": { "orderId": "8b0e5d1c-2f3a-4b5c-9d6e-7f8a9b0c1d2e", "number": 42, "items": [ { "productId": "1f2a3b4c-5d6e-4f70-8192-a3b4c5d6e7f8", "name": "Chocolate cake", "quantity": 2, "unitPrice": "15.00", "lineTotal": "30.00" } ], "subtotal": "30.00", "discount": "3.00", "couponCode": "WELCOME", "deliveryFee": "5.00", "total": "32.00", "currency": "USD", "deliveryMethod": "DELIVERY", "customer": { "name": "Ana Pérez", "phone": "584121234567", "address": "123 Main St, Miami", "note": "Ring 2B" } } }}Payout events
| Event | data fields |
|---|---|
payout.created | payoutId, amountUsdt, feeUsdt, netUsdt, destinationAddress, network, status, createdAt |
payout.completed | payoutId, amountUsdt, feeUsdt, netUsdt, destinationAddress, network, txHash |
payout.failed | payoutId, amountUsdt, feeUsdt, netUsdt, destinationAddress, network, refunded |
amountUsdtis what was debited from your balance.feeUsdtis the payout fee.netUsdtis what's sent:amountUsdt = feeUsdt + netUsdt.- If the payout fails, the full
amountUsdtis returned, fee included.
Recurring billing events
PRO and PREMIUM plans only. data.subscription has the shape of a subscription (without installments) and data.installment, that of an installment. Paying each installment also emits the usual order.* events.
| Event | When | data fields |
|---|---|---|
subscription.created | You subscribed a customer, from the dashboard or the API. | subscription |
subscription.installment.created | The period's installment was generated, a few days before the due date depending on the plan. | subscription, installment (with checkoutUrl) |
subscription.installment.paid | Your customer paid the installment. | subscription, installment (with orderId) |
subscription.installment.overdue | The installment went unpaid past its due date (the day after). | subscription, installment |
subscription.paused | You paused the subscription. | subscription |
subscription.resumed | You resumed it. Paused periods aren't charged. | subscription |
subscription.cancelled | You cancelled it: pending installments are voided. | subscription |
subscription.ended | The last installment of a plan with a fixed number of installments was paid. | subscription |
Declared, not emitted yet
You can subscribe to these events, but they won't arrive until the flow that produces them exists. The dashboard shows them disabled.
| Event | Why it doesn't arrive |
|---|---|
order.cancelled | There's no order cancellation. |
order.refunded | There's no refund flow. |
merchant.kyb.approved | The verification result only shows in the dashboard. |
merchant.kyb.rejected | The verification result only shows in the dashboard. |