Webhook Events Reference#
Complete list of all webhook events you can subscribe to.
Overview#
Webhooks allow your application to receive real-time notifications when events occur in AuxCORE. Instead of polling for changes, AuxCORE sends HTTP POST requests to your configured endpoint.
AuxCORE emits seventeen merchant events: eight transaction events, two checkout-session events and seven dispute events. The first ten are the default set — POST /public/register-webhook subscribes to them when you send no events. Dispute events are delivered only when you list them. Subscribing to an unknown name is rejected with 400 UNKNOWN_EVENT_TYPE. Wildcards (transaction.*) and payload filters are not supported.
Note: Subscription, invoice, settlement, fraud, batch and refund-queue events are not available as webhooks. Use the REST API to read their state.
invoice.paidis the one exception outside this list: it is posted to a per-invoicewebhookUrl(unsigned) — see Invoices.
Event Structure#
All webhook events follow this structure:
{
"id": "0b8f3d2c-5a1e-4f6b-9c7d-2e4a6b8c0d1f",
"type": "transaction.approved",
"created": "2026-01-28T12:34:56.000Z",
"data": {
...event-specific data...
},
"metadata": {
"tenantId": "your-tenant-id",
"merchantId": "550e8400-e29b-41d4-a716-446655440000"
}
}| Field | Type | Description |
|---|---|---|
id |
string | Unique event ID (also sent as X-Webhook-Event-ID) — use it to de-duplicate |
type |
string | Event type |
created |
string | ISO 8601 time the event was created |
data |
object | Event-specific data |
metadata.tenantId |
string | Your tenant ID |
metadata.merchantId |
string | Merchant the event belongs to |
Event Summary#
| Event | Sent when |
|---|---|
transaction.approved |
A sale or authorization is approved, or an ACH payment later settles |
transaction.pending |
A payment is accepted but not yet settled (for example ACH) |
transaction.in_review |
A payment is approved by the processor but held by a Transaction Rule until the merchant reviews it |
transaction.declined |
A payment is declined |
transaction.voided |
A transaction is voided |
transaction.refunded |
A refund is approved |
transaction.refund_failed |
A refund is declined by the processor |
transaction.returned |
An ACH debit is returned by the bank after it was accepted |
session.cancelled |
The shopper cancels a hosted checkout session |
session.expired |
A hosted checkout session expires, or the shopper never completes payment |
chargeback.received |
A dispute case is opened (API, processor notification or bank-file import) |
transaction.chargeback |
A transaction is flagged as charged back from the dashboard |
chargeback.open |
A case's status changes to open |
chargeback.under_review |
A case's status changes to under_review |
chargeback.won |
A case's status changes to won |
chargeback.lost |
A case's status changes to lost — including when the merchant accepts the dispute |
chargeback.expired |
A case's status changes to expired (lapsed or prevented) |
Captures do not emit an event; a capture changes the transaction's type to capture. Delivering a webhook.test event is also possible from the test endpoint (see below).
Transaction Events#
transaction.approved, transaction.pending, transaction.in_review, transaction.declined, transaction.voided, transaction.refunded, transaction.refund_failed and transaction.returned all carry the same data body. Only type and the transaction fields (status, responseCode, responseText, originalTransactionId) differ.
{
"id": "0b8f3d2c-5a1e-4f6b-9c7d-2e4a6b8c0d1f",
"type": "transaction.approved",
"created": "2026-01-28T12:34:56.000Z",
"data": {
"transactionId": "TXN-1776037573138-56123064",
"id": "550e8400-e29b-41d4-a716-446655440020",
"type": "sale",
"status": "approved",
"amount": 153.75,
"baseAmount": 150.00,
"convenienceFee": 3.75,
"tipAmount": 0,
"taxAmount": 0,
"currency": "USD",
"authCode": "123456",
"responseCode": "100",
"responseText": "Approved",
"gatewayTransactionId": "8812734455",
"gatewayName": "NMI",
"provider": "NMI",
"paymentMethod": "card",
"cardLast4": "1111",
"cardBrand": "visa",
"orderId": "1042",
"invoiceNumber": null,
"billingEmail": "customer@example.com",
"originalTransactionId": null,
"requestOrigin": "api",
"failureReason": null,
"returnCode": null,
"payment": { "method": "card" },
"velocityReviewStatus": null,
"merchantId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-01-28T12:34:56.000Z"
},
"metadata": {
"tenantId": "your-tenant-id",
"merchantId": "550e8400-e29b-41d4-a716-446655440000"
}
}transactionIdis the human-readable reference;idis the UUID used in API paths.payment.methodiscard,ach,cryptoorcash.failureReasonis a readable reason ontransaction.declined,transaction.returnedandtransaction.refund_failed(for exampleInsufficient funds);nullotherwise.returnCodeis the ACH return code (R01,R02, …) ontransaction.returned;nullotherwise.- Hosted checkout payments also carry
sessionIdandrefNo. statusvalues:pending,approved,declined,settled,voided,refunded,error,reversed,processing.velocityReviewStatusisin_reviewwhile a merchant Transaction Rule holds the payment, thenapprovedordenied;nullwhen no rule held it.
transaction.approved#
A sale or authorization is approved (status: "approved"), or a pending ACH payment later settles. For ACH, this event — not transaction.pending — means the money arrived.
When fired: After the gateway approves the payment.
transaction.pending#
A payment is accepted but not final — typically ACH (status: "pending").
When fired: After the payment is accepted for processing.
transaction.in_review#
The processor approved the payment (status: "approved", velocityReviewStatus: "in_review"), but one of the merchant's Transaction Rules flagged it, so it is held from settlement until the merchant reviews it. The payment is not complete: keep the order on hold.
When fired: After the gateway approves a flagged payment. The merchant's decision follows as transaction.approved (Approve) or transaction.voided (Deny).
transaction.declined#
status: "declined". failureReason is the reason to show or log, responseCode an NMI-style decline code and responseText the processor text (see Error Codes). A payment a merchant Transaction Rule denied before it reached the processor has responseCode: "VELOCITY_DENIED".
When fired: After the gateway declines the payment.
transaction.voided#
status: "voided" — fired for voids of approved sales and authorizations, pending ACH payments and unbatched TSYS captures.
When fired: After the void succeeds.
transaction.refunded#
Fired for the refund transaction (type: "refund", status: "refunded"). originalTransactionId points at the sale.
When fired: After the processor approves the refund.
transaction.refund_failed#
Fired for a refund the processor declined (type: "refund", status: "declined"); failureReason says why. Gateway declines are added to the Refund Decline Queue, but nothing retries them automatically — a user must retry from the queue (see Refund Queue).
When fired: After the processor declines the refund.
transaction.returned#
An ACH debit came back from the receiving bank (R01 insufficient funds, R02 account closed, and so on) days after it was accepted. status is reversed, returnCode the R-code (R01) and failureReason the reason, for example ACH returned (R01) — Insufficient funds.
When fired: When the bank return is reconciled. For hosted-checkout payments the same body is also sent as a legacy transaction.declined event, so a store subscribed to both receives two events.
Session Events#
Fired for hosted checkout sessions created with POST /api/v1/public/checkout-session.
{
"id": "5d6e7f80-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
"type": "session.expired",
"created": "2026-01-28T12:34:56.000Z",
"data": {
"sessionId": "cs_3f9c2b7e0d",
"refNo": "REF-1042",
"orderId": "1042",
"merchantId": "550e8400-e29b-41d4-a716-446655440000",
"transactionId": "TXN-1776037573138-56123064",
"status": "error",
"reason": "checkout_not_completed",
"timestamp": "2026-01-28T12:34:56.000Z"
},
"metadata": {
"tenantId": "your-tenant-id",
"merchantId": "550e8400-e29b-41d4-a716-446655440000"
}
}The example above is the crypto variant (payment started but never completed), which adds transactionId, status: "error" and reason. When the hosted page reports the cancel or expiry itself, data carries only sessionId, refNo, orderId, merchantId and timestamp.
session.cancelled#
The shopper cancelled on the hosted page.
session.expired#
The session expired or the shopper never completed payment.
Dispute Events#
Fired by dispute (chargeback) cases. They are not part of the default subscription: list each one you want in events.
{
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"type": "chargeback.received",
"created": "2026-01-28T12:34:56.000Z",
"data": {
"id": "2c4e6a8b-0d1f-4a3c-9e5b-7d9f1b3d5f7a",
"caseNumber": "CB-2026-00042",
"merchantId": "550e8400-e29b-41d4-a716-446655440000",
"originalTransactionId": "550e8400-e29b-41d4-a716-446655440020",
"auxcoreStatus": "open",
"networkStage": null,
"networkStageUpdatedAt": null,
"outcome": "pending",
"status": "open",
"chargebackType": "fraud",
"reasonCode": "10.4",
"transactionAmount": 150.75,
"disputeAmount": 150.75,
"currency": "USD",
"receivedDate": "2026-01-28T00:00:00.000Z",
"dueDate": "2026-02-07T00:00:00.000Z"
},
"metadata": {
"tenantId": "your-tenant-id",
"merchantId": "550e8400-e29b-41d4-a716-446655440000"
}
}Every dispute event carries this data body:
| Field | Description |
|---|---|
id, caseNumber |
The dispute case |
originalTransactionId |
The disputed transaction |
auxcoreStatus |
open, action_required, submitted, under_review or closed |
networkStage |
The card network's stage as reported by the processor, shown verbatim; null until reported |
outcome |
pending, merchant_won, merchant_lost, merchant_accepted or prevented |
status |
Summary status: open, under_review, won, lost or expired — the chargeback.<status> events are named after it |
chargebackType |
first_chargeback, pre_arbitration, arbitration, retrieval, fraud, duplicate, not_received, not_as_described, cancelled, credit_not_processed or other |
reasonCode, transactionAmount, disputeAmount, currency, receivedDate, dueDate |
Case details; respond before dueDate |
chargeback.<status>fires only when the summarystatuschanges. An update that changes onlyauxcoreStatus,networkStageoroutcomewithout movingstatussends no event — read the case with the Disputes API when you need every change.transaction.chargebackis a separate, older name for a dispute raised by flagging the transaction in the dashboard; it carries the same body.
Platform Events#
batch.resubmit exists in the event registry but is dispatched only to platform (system) endpoints. A merchant endpoint may list it, but never receives it.
Webhook Delivery#
Headers Sent#
AuxCORE sends each event to the URL you registered:
POST https://your-app.example.com/webhooks/auxcore
Content-Type: application/json
User-Agent: AuxVault-Webhooks/1.0
X-Webhook-Signature: t=1769603696,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
X-Webhook-Event-Type: transaction.approved
X-Webhook-Event-ID: 0b8f3d2c-5a1e-4f6b-9c7d-2e4a6b8c0d1f
X-Webhook-Delivery-ID: 7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4fX-Webhook-Signature is t=<unix seconds>,v1=<hex HMAC-SHA256>, where the HMAC is computed with your endpoint secret over "<t>.<raw request body>". Reject signatures older than 5 minutes. See Webhooks for verification code.
Retry Logic#
A delivery fails on any non-2xx response, a network error, or no response within 30 seconds. Failed deliveries are retried until the endpoint's maxRetries attempts (default 3, including the first) have been made.
| Attempt | Delay (defaults) |
|---|---|
| 1 | Immediate |
| 2 | ~1 minute |
| 3 | ~2 minutes |
The delay before attempt n + 1 is retryDelaySeconds × 2^(n − 1) (default retryDelaySeconds is 60). Retries are picked up by a sweep that runs about once a minute. After the last attempt the delivery is marked failed; retry it manually with POST /api/v1/webhooks/deliveries/:deliveryId/retry.
Expected Response#
Your endpoint should return a 2xx status code promptly:
HTTP/1.1 200 OKBest Practices#
DO:#
- Verify signatures - Ensure webhooks are from AuxCORE
- Respond quickly - Return 200 and process asynchronously
- Handle duplicates - Use the event ID for idempotency
- Log all events - For debugging and audit trail
- Test thoroughly - Use the Sandbox environment
DON'T:#
- Don't do heavy processing - Respond quickly, process later
- Don't ignore signatures - Always verify
- Don't skip error handling - Handle all scenarios
- Don't expose an unauthenticated endpoint - Use HTTPS and verify the signature
- Don't retry synchronously - We handle retries
Testing Webhooks#
Test Event Endpoint#
Send a webhook.test event to an endpoint:
curl -X POST https://uat.auxcore.net/api/v1/webhooks/endpoints/ENDPOINT_ID/test \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"The test event has type: "webhook.test" and is signed like a real delivery.
Next Steps#
Need help? Contact support@auxcore.net