Skip to navigation

Transaction Webhooks

Transaction webhooks tell you when a transaction is recorded and each time its status changes. Every transaction event has the same payload, so one handler can cover them all. For the envelope, signature, duplicates and retries, see the Webhooks Overview.

Transaction Lifecycle

Authorized (1) → Batched (2) → Captured (3) → Processed (5)

A successful transaction moves along this path. You get transaction.entered when it’s recorded, then transaction.batched, transaction.captured and transaction.processed as its status changes. trans_status_id is where the transaction is now, which is why most settled transactions show 5.

Off this path, Declined (4) and Rejected (22) end the transaction, and you get transaction.decline or transaction.reject. A transaction can also be Voided (7), or later Refunded (6) or Partially Refunded (63).

Events

Event TypeSent when
transaction.enteredA transaction is recorded, whatever its outcome.
transaction.entered.<source>Also sent, with transaction.entered, for a transaction from that source, such as transaction.entered.hpp. See Sources.
transaction.batchedThe transaction is batched.
transaction.capturedThe transaction is captured.
transaction.processedThe transaction is processed.
transaction.declineThe transaction is declined.
transaction.rejectThe transaction is rejected.
transaction.voidedThe transaction is voided.
transaction.refundThe transaction is fully refunded.
transaction.partialrefundPart of the transaction is refunded. Sent again each time the refunded amount changes.

One transaction can send several events. A transaction declined when it’s entered sends transaction.entered and then transaction.decline. event_table_pk is the same on every event for the same transaction, so use it to match them up.

Sources

Every transaction payload carries the source the transaction came from, as source and transact_source_id. Each source also has its own event, transaction.entered.<source>, sent alongside transaction.entered. Subscribe to a per-source event if you only want transactions from one source.

sourcetransact_source_idSourcePer-source event
rmvt1Run Merchant virtual terminaltransaction.entered.rmvt
hpp2Hosted Payment Pagetransaction.entered.hpp
api3Run Developer APItransaction.entered.api
thirdparty4Imported from a third-party processor feedtransaction.entered.thirdparty
billing5Billing plan paymenttransaction.entered.billing
invoicing6Invoice paymenttransaction.entered.invoicing
clover21Clover Connectortransaction.entered.clover

Both fields are null when the source isn’t known. New sources may be added.

Examples

transaction.entered

{
"event_type": "transaction.entered",
"source_id": "104000",
"timestamp": "2026-10-15T14:49:28.181Z",
"payload": {
"event_table_pk": 219000000,
"mid": "800000000000",
"trans_id": "076400000000",
"card_number": "9400000000001111",
"name_on_account": "Jane Example",
"expiration": "202812",
"auth_code": "PPS123",
"response_text": "Approval",
"response_code": "000",
"tokenized_card": "1a2b3c4d5e6f7a8b",
"order_id": "ORDER-1001",
"amount": 45.00,
"refunded_amount": null,
"transaction_timestamp": "2026-10-15T14:49:28.965+00:00",
"trans_status_id": 1,
"invoice_id": "INV-1001",
"transact_source_id": 1,
"source": "rmvt",
"timestamp": "2026-10-15T14:49:28.089+00:00"
},
"metadata": {
"webhook_id": "wh_600000",
"attempt": 1,
"idempotency_key": "4f1c0a9e2b7d4c3e8a6b5d0f1e2c3b4a"
}
}

This card was saved, so tokenized_card holds its stored-card token. In most transactions it is null.

transaction.decline

{
"event_type": "transaction.decline",
"source_id": "104000",
"timestamp": "2026-10-15T15:05:12.181Z",
"payload": {
"event_table_pk": 219000001,
"mid": "800000000000",
"trans_id": "076400000001",
"card_number": "9400000000001111",
"name_on_account": "Sam Example",
"expiration": "202812",
"auth_code": null,
"response_text": "Insufficient Funds",
"response_code": "051",
"tokenized_card": null,
"order_id": "ORDER-1002",
"amount": 150.00,
"refunded_amount": null,
"transaction_timestamp": "2026-10-15T15:05:12.965+00:00",
"trans_status_id": 4,
"invoice_id": null,
"transact_source_id": 2,
"source": "hpp",
"timestamp": "2026-10-15T15:05:12.089+00:00"
},
"metadata": {
"webhook_id": "wh_600003",
"attempt": 1,
"idempotency_key": "0a1b2c3d4e5f60718293a4b5c6d7e8f9"
}
}

transaction.reject

{
"event_type": "transaction.reject",
"source_id": "104000",
"timestamp": "2026-10-15T15:12:40.181Z",
"payload": {
"event_table_pk": 219000002,
"mid": "800000000000",
"trans_id": "076400000002",
"card_number": "9400000000001111",
"name_on_account": "Alex Example",
"expiration": "202812",
"auth_code": null,
"response_text": "Rejected",
"response_code": "059",
"tokenized_card": null,
"order_id": "ORDER-1003",
"amount": 999.99,
"refunded_amount": null,
"transaction_timestamp": "2026-10-15T15:12:40.965+00:00",
"trans_status_id": 22,
"invoice_id": null,
"transact_source_id": 3,
"source": "api",
"timestamp": "2026-10-15T15:12:40.089+00:00"
},
"metadata": {
"webhook_id": "wh_600004",
"attempt": 1,
"idempotency_key": "1b2c3d4e5f60718293a4b5c6d7e8f90a"
}
}

transaction.refund

{
"event_type": "transaction.refund",
"source_id": "104000",
"timestamp": "2026-10-15T16:20:05.181Z",
"payload": {
"event_table_pk": 219000004,
"mid": "800000000000",
"trans_id": "076400000004",
"card_number": "9400000000001111",
"name_on_account": "Jane Example",
"expiration": "202812",
"auth_code": "PPS789",
"response_text": "Approval",
"response_code": "000",
"tokenized_card": null,
"order_id": "ORDER-1005",
"amount": 45.00,
"refunded_amount": 45.00,
"transaction_timestamp": "2026-10-15T16:20:05.965+00:00",
"trans_status_id": 6,
"invoice_id": "INV-1005",
"transact_source_id": 1,
"source": "rmvt",
"timestamp": "2026-10-15T16:20:05.089+00:00"
},
"metadata": {
"webhook_id": "wh_600005",
"attempt": 1,
"idempotency_key": "2c3d4e5f60718293a4b5c6d7e8f90a1b"
}
}

transaction.partialrefund

{
"event_type": "transaction.partialrefund",
"source_id": "104000",
"timestamp": "2026-10-15T16:31:47.181Z",
"payload": {
"event_table_pk": 219000003,
"mid": "800000000000",
"trans_id": "076400000003",
"card_number": "9400000000001111",
"name_on_account": "Jane Example",
"expiration": "202812",
"auth_code": "PPS456",
"response_text": "Approval",
"response_code": "000",
"tokenized_card": null,
"order_id": "ORDER-1004",
"amount": 99.99,
"refunded_amount": 25.00,
"transaction_timestamp": "2026-10-15T16:31:47.965+00:00",
"trans_status_id": 63,
"invoice_id": "INV-1004",
"transact_source_id": 5,
"source": "billing",
"timestamp": "2026-10-15T16:31:47.089+00:00"
},
"metadata": {
"webhook_id": "wh_600006",
"attempt": 1,
"idempotency_key": "3d4e5f60718293a4b5c6d7e8f90a1b2c"
}
}

refunded_amount is the total refunded so far, not the amount of the latest refund.

Payload Fields

FieldData TypeComments
event_table_pkIntegerRun’s ID for the transaction record.
midStringMerchant ID assigned by the processor.
trans_idStringTransaction ID from the gateway.
card_numberStringThe card as returned by the gateway. Always present. Never a raw card number.
tokenized_cardStringStored-card token. Present only when the card is saved; usually null. Not the same as card_number.
name_on_accountStringCardholder name.
expirationStringCard expiration date.
auth_codeStringAuthorization code. null if the transaction wasn’t authorized.
response_textStringGateway response message.
response_codeStringGateway response code.
order_idStringOrder ID sent with the transaction.
amountNumberTransaction amount.
refunded_amountNumberTotal refunded so far. null if nothing has been refunded.
transaction_timestampStringWhen the transaction took place (UTC).
trans_status_idIntegerThe transaction’s status when the event was sent. See Status IDs.
invoice_idStringInvoice ID sent with the transaction. null if there is none.
transact_source_idIntegerNumeric ID of the transaction’s source. See Sources.
sourceStringThe transaction’s source, such as hpp or api. See Sources.
timestampStringWhen the event was created (UTC).

Status IDs

Act on event_type, not trans_status_id. The status ID is there for reference. There is no “approved” status: an approved payment is one that reaches Authorized and moves on. The transaction.decline and transaction.reject events tell you when it didn’t.

These are the statuses that send an event:

trans_status_idStatusEvent Sent
1AuthorizedNone of its own. Every new transaction sends transaction.entered, whatever its status.
2Batchedtransaction.batched
3Capturedtransaction.captured
5Processedtransaction.processed
4Declinedtransaction.decline
22Rejectedtransaction.reject
7Voidedtransaction.voided
6Refundedtransaction.refund
63Partially Refundedtransaction.partialrefund

trans_status_id can hold a value not listed here, for example on transaction.entered. Don’t fail on one you don’t recognize.