Overview
Cartevo webhooks notify your system in near real‑time about account events (card creation, funding, withdrawals, errors, etc.).
- Method: POST
- Format: JSON
- Headers:
Content-Type: application/json
- Expected response: any HTTP 2xx is treated as success (response body is ignored)
Your webhook URL is configured on your company account. For every event, Cartevo sends an HTTP request with the following shape:
{
"event": "<event_name>",
"data": {
/* event-specific payload */
}
}
Content-Type: application/json
X-Cartevo-Signature: t=<unix-seconds>,v1=<hex-hmac-sha256>
Content-Type is always application/json.
X-Cartevo-Signature is present only when webhook signing is enabled for your company (a signing secret is configured). When signing is disabled, no signature header is sent.
- No other custom headers (e.g.
User-Agent, X-Webhook-Id, X-Webhook-Timestamp) are guaranteed — do not depend on them.
Retry policy
If delivery fails (non‑2xx response or network error), Cartevo automatically retries. There is 1 initial attempt + 3 retries = 4 total deliveries, spaced 5 seconds apart.
| Attempt | Delay | Elapsed |
|---|
| 1 (initial) | 0s | 0s |
| 2 (retry 1) | 5s | 5s |
| 3 (retry 2) | 5s | 10s |
| 4 (retry 3) | 5s | 15s |
- Max retries: 3 (4 total attempts including the initial delivery)
- Timeout: 10 seconds per attempt
- Logging: every attempt is logged; after the final retry fails, delivery is marked permanently failed.
Verifying webhook signatures
When webhook signing is enabled for your company, every delivery carries an X-Cartevo-Signature header so you can confirm the request genuinely came from Cartevo and was not tampered with.
Header format:
X-Cartevo-Signature: t=<unix-seconds>,v1=<hex-hmac-sha256>
| Part | Description |
|---|
t | Unix timestamp (seconds) when the signature was generated |
v1 | Lowercase hex-encoded HMAC-SHA256 signature |
How the signature is computed:
- Take the raw request body exactly as received — do not re-serialize the JSON.
- Build the signed string
"{t}.{rawBody}" — the timestamp, a literal dot (.), then the raw body.
- Compute
HMAC-SHA256(signed_string, your_signing_secret) and hex-encode it. That value is v1.
Your signing secret is a 64-character hex string available in your company webhook settings. The signature is generated once when the event is enqueued and replayed verbatim on retries, so the same t/v1 may arrive on more than one delivery attempt.
Verification (Node.js):
import crypto from "crypto";
function verifyCartevoSignature(rawBody, header, secret, toleranceSeconds = 300) {
// header example: "t=1736337600,v1=9a1c..."
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=").map((s) => s.trim()))
);
const { t, v1 } = parts;
if (!t || !v1) return false;
// Optional: reject stale timestamps to mitigate replay attacks
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
try {
return crypto.timingSafeEqual(
Buffer.from(v1, "hex"),
Buffer.from(expected, "hex")
);
} catch {
return false;
}
}
Always verify against the raw, unparsed body. If your framework parses JSON before you can read the raw bytes, configure it to expose the raw body (e.g. Express: express.json({ verify: (req, _res, buf) => { req.rawBody = buf; } })). Re-serializing the parsed object changes the bytes and the signature will not match.
Field naming convention
All webhook payload keys use snake_case (e.g. transaction_id, card_id, created_at). A small number of legacy events still emit a few camelCase keys (e.g. cardId, transactionId); these are flagged inline in each event’s field table and will be migrated to snake_case in a future release. Always consult the field table for the canonical key spelling per event.
🚨 Tip: treat webhooks as at‑least‑once deliveries. Implement idempotency/deduplication on your receiver using stable business identifiers (e.g., transaction_id, card.id, wallet_id).
Setting Up Webhooks
Set your webhook URL in your company settings:
Supported Events
Payment Events
payment.collect
Emitted when a payment collection (pay‑in) is initiated. Note: this fires when collection begins; the eventual outcome (SUCCESS / FAILED) reaches you via the polled GET /payment/transactions/{id}/status endpoint or via your notify_url if one was supplied.
{
"event": "payment.collect",
"data": {
"transaction_id": "550e8400-e29b-41d4-a716-446655440000",
"external_id": "your-idempotency-key-001",
"status": "PENDING",
"amount": 1000,
"currency": "XAF",
"country": "CM",
"operator": "mtn",
"phone_number": "237600000000",
"initiated_at": "2025-01-08T12:00:00.000Z"
}
}
Fields:
| Field | Type | Description |
|---|
transaction_id | string | Cartevo-side transaction identifier (UUID) |
external_id | string | The idempotency key you supplied at collection initiation, if any |
status | string | One of PENDING, PROCESSING, SUCCESS, FAILED |
amount | number | Amount in currency units |
currency | string | ISO 4217 currency code (e.g. XAF, XOF, CDF, USD) |
country | string | ISO 3166-1 alpha-2 country code |
operator | string | Mobile-money operator code (e.g. mtn, orange, moov) |
phone_number | string | The end-user phone number being charged |
initiated_at | string | ISO 8601 timestamp when the collection was initiated (UTC) |
Card Events
card.created
Emitted when a new card is successfully created for a customer.
Payload:
{
"event": "card.created",
"data": {
"card": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"customer_id": "8d4f2a1b-5c3e-4d7f-9a6b-2e1c8f9d0a3b",
"brand": "VISA",
"masked_number": "4111********1111",
"balance": 100.0,
"currency": "USD"
},
"card_issuance": {
"status": "SUCCESS",
"transaction_id": "txn_3f8a9b2c4d6e7f8a9b0c1d2e",
"amount": 2.0,
"description": "Card issuance fee"
},
"card_fund": {
"status": "SUCCESS",
"transaction_id": "txn_5b7c9d2e4f6a8b1c3d5e7f9a",
"amount": 100.0,
"description": "Initial card funding"
}
}
}
card fields:
| Field | Type | Description |
|---|
id | string | Unique card identifier (UUID) |
customer_id | string | Customer who owns the card (UUID) |
brand | string | Card brand. One of VISA, MASTERCARD |
masked_number | string | Card number with all but the last 4 digits replaced by * |
balance | number | Card balance in currency units |
currency | string | Card currency (always USD) |
card_issuance fields:
| Field | Type | Description |
|---|
status | string | Issuance status. One of SUCCESS, FAILED, PENDING |
transaction_id | string | Transaction ID for the issuance fee |
amount | number | Issuance fee in USD |
description | string | Human-readable description of the issuance transaction |
card_fund fields:
| Field | Type | Description |
|---|
status | string | Funding status. One of SUCCESS, FAILED, PENDING |
transaction_id | string | Transaction ID for the initial card funding |
amount | number | Initial funding amount in USD |
description | string | Human-readable description of the funding transaction |
card.fund
Emitted when a card is funded with money from a wallet.
Payload:
{
"event": "card.fund",
"data": {
"transaction_id": "txn_ghi789klm345",
"card_id": "card_abc123xyz789",
"amount": 50.0,
"currency": "USD",
"fee_amount": 0.0
}
}
Fields:
| Field | Type | Description |
|---|
transaction_id | string | Transaction reference |
card_id | string | Card being funded |
amount | number | Amount added to card |
currency | string | Transaction currency |
fee_amount | number | Fee charged for funding (usually 0) |
card.withdraw
Emitted when money is withdrawn from a card back to the wallet.
Payload:
{
"event": "card.withdraw",
"data": {
"transaction_id": "txn_nop678qrs234",
"card_id": "card_abc123xyz789",
"amount": 30.0,
"currency": "USD",
"fee_amount": 0.0
}
}
Fields:
| Field | Type | Description |
|---|
transaction_id | string | Transaction reference |
card_id | string | Card being withdrawn from |
amount | number | Amount withdrawn |
currency | string | Transaction currency |
fee_amount | number | Fee charged for withdrawal (usually 0) |
card.withdraw.failed
Emitted when a card withdrawal attempt fails.
Payload:
{
"event": "card.withdraw.failed",
"data": {
"transaction_id": "txn_tuv901wxy567",
"card_id": "card_abc123xyz789",
"amount": 200.0,
"error": "Insufficient balance or provider error"
}
}
Fields:
| Field | Type | Description |
|---|
transaction_id | string | Failed transaction reference |
card_id | string | Card attempted to withdraw from |
amount | number | Amount that failed to withdraw |
error | string | Error message describing failure reason |
card.terminated
Emitted when a card is permanently terminated and any remaining balance is refunded to the company’s USD wallet.
Payload:
{
"event": "card.terminated",
"data": {
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"cardNumber": "****1234",
"status": "TERMINATED",
"terminatedAt": "2025-01-08T12:00:00.000Z",
"refundAmount": 50.0,
"refundProcessed": true,
"reason": "Card terminated"
}
}
Fields:
| Field | Type | Description |
|---|
cardId | string | Unique identifier of the terminated card (UUID) |
cardNumber | string | Masked card number showing only the last 4 digits (e.g., ****1234) |
status | string | Always "TERMINATED" for this event |
terminatedAt | string | ISO 8601 timestamp when the card was terminated |
refundAmount | number | Amount refunded to the company’s USD wallet (0 if card had no balance) |
refundProcessed | boolean | Indicates whether the refund was successfully processed (true or false) |
reason | string | Reason for termination (typically "Card terminated") |
Important Notes:
- When a card is terminated, any remaining balance is automatically refunded to the company’s USD wallet
- The card balance is set to zero and the card becomes unusable
- This action is irreversible - once terminated, a card cannot be reactivated
- Webhook failures do not prevent card termination from completing
- A termination may be customer/company-initiated or provider-initiated (e.g. a fraud/risk block). For provider-initiated terminations the payload is lighter and carries
reason: "provider_terminated" and previousBalance instead of the refund fields:
{
"event": "card.terminated",
"data": {
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"status": "TERMINATED",
"reason": "provider_terminated",
"previousBalance": 1.12
}
}
card.verification.completed
Emitted when a card account is successfully verified by a merchant — a $0.00 verification hold some merchants place when a card is added (e.g. to a wallet or subscription).
Payload:
{
"event": "card.verification.completed",
"data": {
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"status": "VERIFIED",
"message": "Card account verified",
"merchant": {
"name": "Google TEMPORARY HOLD"
},
"reference": "eebade9a-2437-4ecb-8dc6-c75ed1ba7eac"
}
}
Fields:
| Field | Type | Description |
|---|
cardId | string | Verified card identifier (UUID, camelCase — legacy) |
status | string | Always "VERIFIED" for this event |
message | string | Verification message from the network (e.g. "Card account verified") |
merchant | object | Merchant that performed the verification (name), or null |
reference | string | Provider event reference for this verification |
Transaction Events
transaction.settlement.completed
Emitted when a transaction is settled/cleared.
{
"event": "transaction.settlement.completed",
"data": {
"transactionId": "txn_abc123",
"cardId": "card_xyz789",
"amount": 25.0,
"currency": "USD",
"type": "SETTLEMENT",
"status": "SUCCESS",
"createdAt": "2025-01-06T13:00:00Z",
"merchant": {
"name": "Merchant Ltd",
"country": "US",
"city": "Seattle"
}
}
}
transaction.authorization.created
Emitted when a card payment authorization succeeds.
Payload:
{
"event": "transaction.authorization.created",
"data": {
"transactionId": "txn_abc123",
"cardId": "card_xyz789",
"amount": 25.0,
"currency": "USD",
"type": "AUTHORIZATION",
"status": "SUCCESS",
"createdAt": "2025-01-06T13:00:00Z",
"merchant": {
"name": "Amazon.com",
"country": "US",
"city": "Seattle"
}
}
}
Fields:
| Field | Type | Description |
|---|
transactionId | string | Transaction identifier |
cardId | string | Card used for transaction |
amount | number | Transaction amount |
currency | string | Transaction currency |
type | string | Transaction type (AUTHORIZATION) |
status | string | Transaction status (SUCCESS) |
createdAt | string | ISO 8601 timestamp |
merchant | object | Merchant information (name, country, city) |
mcc | string | Merchant Category Code (optional) |
mid | string | Merchant ID (optional) |
approvalCode | string | Authorization approval code (optional) |
cardBalanceBefore | number | Card balance before (optional) |
cardBalanceAfter | number | Card balance after (optional) |
transaction.authorization.declined
Emitted when a payment authorization is declined.
Payload:
{
"event": "transaction.authorization.declined",
"data": {
"transactionId": "txn_def456",
"cardId": "card_xyz789",
"customerId": "cust_def456",
"amount": 150.0,
"currency": "USD",
"type": "AUTHORIZATION",
"status": "FAILED",
"createdAt": "2025-01-06T13:00:00Z",
"merchant": {
"name": "Expensive Store",
"country": "US"
},
"declineReason": "Insufficient funds"
}
}
Fields:
| Field | Type | Description |
|---|
transactionId | string | Transaction identifier |
cardId | string | Card used for transaction |
customerId | string | Customer identifier |
amount | number | Transaction amount |
currency | string | Transaction currency |
type | string | Transaction type (AUTHORIZATION) |
status | string | Transaction status (FAILED) |
createdAt | string | ISO 8601 timestamp |
merchant | object | Merchant information |
declineReason | string | Reason for decline |
transaction.preauthorization.created
Emitted when a pre-authorization hold is placed on a card — an amount is reserved at the merchant but not yet finally captured (common for hotels, car rentals, fuel pumps, etc.). The hold is later either settled (transaction.settlement.completed) or released/reversed (transaction.reversal.completed).
Payload:
{
"event": "transaction.preauthorization.created",
"data": {
"transactionId": "pre-67367357",
"cardId": "card_xyz789",
"amount": 1.0,
"currency": "USD",
"type": "PRE_AUTHORIZATION",
"status": "PENDING",
"merchant": {
"name": "BOOKING.COM"
}
}
}
Fields:
| Field | Type | Description |
|---|
transactionId | string | Pre-authorization transaction identifier |
cardId | string | Card the hold was placed on |
amount | number | Amount held (reserved) |
currency | string | Transaction currency |
type | string | Always "PRE_AUTHORIZATION" for this event |
status | string | Always "PENDING" (the hold is not yet captured) |
merchant | object | Merchant information (name, country, city) |
transaction.reversal.completed
Emitted when a transaction is reversed (usually within 24 hours).
Payload:
{
"event": "transaction.reversal.completed",
"data": {
"transactionId": "txn_pqr678",
"cardId": "card_xyz789",
"amount": 25.0,
"currency": "USD",
"type": "REVERSAL",
"status": "SUCCESS",
"merchant": {
"name": "Amazon.com",
"country": "US"
},
"reversalReason": "Customer cancelled order",
"createdAt": "2025-01-06T13:00:00Z"
}
}
Fields:
| Field | Type | Description |
|---|
transactionId | string | Transaction identifier |
cardId | string | Card used for transaction |
amount | number | Reversed amount |
currency | string | Transaction currency |
type | string | Transaction type (REVERSAL) |
status | string | Transaction status (SUCCESS) |
merchant | object | Merchant information |
reversalReason | string | Reason for reversal |
createdAt | string | ISO 8601 timestamp |
transaction.refund.completed
Emitted when a refund is processed (usually after settlement).
Payload:
{
"event": "transaction.refund.completed",
"data": {
"transactionId": "txn_stu901",
"cardId": "card_xyz789",
"amount": 25.0,
"currency": "USD",
"type": "REFUND",
"status": "SUCCESS",
"merchant": {
"name": "Amazon.com",
"country": "US"
},
"refundReason": "Product returned",
"createdAt": "2025-01-06T13:00:00Z"
}
}
Fields:
| Field | Type | Description |
|---|
transactionId | string | Transaction identifier |
cardId | string | Card used for transaction |
amount | number | Refunded amount |
currency | string | Transaction currency |
type | string | Transaction type (REFUND) |
status | string | Transaction status (SUCCESS) |
merchant | object | Merchant information |
refundReason | string | Reason for refund |
createdAt | string | ISO 8601 timestamp |
transaction.funding.completed
Emitted when a card funding transaction completes.
{
"event": "transaction.funding.completed",
"data": {
"transactionId": "txn_fund001",
"cardId": "card_xyz789",
"amount": 50.0,
"currency": "USD",
"type": "FUND",
"status": "SUCCESS",
"createdAt": "2025-01-06T12:00:00Z"
}
}
transaction.withdrawal.completed
Emitted when a withdrawal from card completes.
{
"event": "transaction.withdrawal.completed",
"data": {
"transactionId": "txn_wd001",
"cardId": "card_xyz789",
"amount": 30.0,
"currency": "USD",
"type": "WITHDRAW",
"status": "SUCCESS",
"createdAt": "2025-01-06T12:30:00Z"
}
}
transaction.crossborder.charged
Emitted when a cross‑border charge related to a purchase is recorded.
{
"event": "transaction.crossborder.charged",
"data": {
"transactionId": "txn_cb001",
"cardId": "card_xyz789",
"amount": 25.0,
"currency": "USD",
"type": "CROSS_BORDER_CHARGE",
"status": "SUCCESS",
"createdAt": "2025-01-06T13:00:00Z",
"feeAmount": 1.13
}
}
transaction.terminated
Emitted when a termination‑type transaction is recorded for a card.
{
"event": "transaction.terminated",
"data": {
"transactionId": "txn_term001",
"cardId": "card_xyz789",
"amount": 0,
"currency": "USD",
"type": "TERMINATION",
"status": "SUCCESS",
"createdAt": "2025-01-06T15:00:00Z"
}
}
Fee Events
fee.payment_failure.charged
Emitted when a fee is charged for a failed payment transaction.
Payload:
{
"event": "fee.payment_failure.charged",
"data": {
"type": "payment_failure",
"amount": 0.5,
"currency": "USD",
"transactionId": "txn_ghi789",
"description": "Payment failure fee - Expensive Store - 150.00 USD - 01/06/2025, 02:00 PM",
"createdAt": "2025-01-06T14:00:05Z"
}
}
fee.crossborder.charged
Emitted when a cross-border transaction fee is charged.
Payload:
{
"event": "fee.crossborder.charged",
"data": {
"type": "crossborder",
"amount": 1.13,
"currency": "USD",
"transactionId": "txn_jkl012",
"cardId": "card_xyz789",
"description": "Cross-border fee - Amazon.com - 25.00 USD - 01/06/2025, 01:00 PM",
"createdAt": "2025-01-06T13:00:20Z"
}
}
Debt Events
debt.recovery.pending
Notifies you in real time when a payment fee debt has been created because the fee could not be collected from the card or wallet at the time of the transaction. Triggered in two scenarios:
- Payment failure fee — A card payment fails, and the company wallet cannot cover the failure fee.
- Cross-border fee — A cross-border transaction occurs, and the company wallet cannot cover the fee.
Payload:
{
"event": "debt.recovery.pending",
"data": {
"amount": 0.5,
"currency": "USD",
"type": "payment_failure_fee",
"cardId": "56dd86c7-255f-4f76-bbbb-fdb33c55fb6c",
"transactionId": "4e3f4fc1-08d9-49a6-b1af-b6495f0a5c2c",
"originalAmount": 150.0
}
}
Fields:
| Field | Type | Description |
|---|
amount | number | Outstanding fee amount in USD |
currency | string | Always "USD" |
type | string | One of payment_failure_fee, crossborder_fee |
cardId | string | Card associated with the underlying transaction (UUID, camelCase — legacy) |
transactionId | string | Underlying transaction ID (UUID, camelCase — legacy) |
originalAmount | number | Amount of the underlying transaction that produced this fee, in transaction currency |
Purpose:
- Maintain transparency throughout the debt recovery process.
Cross-border fee calculation:
Fee = (Transaction Amount × 2.5%) + $0.50
Example:
Transaction: $25.00
Fee: ($25.00 × 2.5%) + $0.50 = $0.625 + $0.50 = $1.13
Fee collection priority:
- Card balance — Fees are first deducted from the available card balance.
- Wallet balance — If the card balance is insufficient, the company USD wallet is debited.
- Debt creation — If both are insufficient, the remaining amount is recorded as a debt to be settled, and
debt.recovery.pending is sent.
Customer Events
customer.created
Emitted when a new customer is created in the system.
Payload:
{
"event": "customer.created",
"data": {
"id": "8d4f2a1b-5c3e-4d7f-9a6b-2e1c8f9d0a3b",
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"phone_number": "+237600000000",
"country": "Cameroon",
"created_at": "2025-01-07T11:00:00.000Z"
}
}
Fields:
| Field | Type | Description |
|---|
id | string | Unique customer identifier (UUID) |
first_name | string | Customer’s first name |
last_name | string | Customer’s last name |
email | string | Customer’s email address |
phone_number | string | Customer’s phone number in E.164 format |
country | string | Customer’s country (full name, e.g. "Cameroon") |
created_at | string | ISO 8601 timestamp (UTC) |
Best Practices
Response Handling
Always return 200 OK within 10 seconds, before processing:
// GOOD
app.post("/webhooks", async (req, res) => {
// Acknowledge immediately
res.status(200).json({ received: true });
// Process async
processWebhook(req.body.event, req.body.data).catch((error) =>
console.error("Webhook error:", error)
);
});
// BAD
app.post("/webhooks", async (req, res) => {
// Processing delays response
await processWebhook(req.body.event, req.body.data);
res.status(200).json({ received: true });
});
Idempotency
Webhooks may be delivered more than once. Always check for duplicates using transaction_id, card.id, or wallet_id:
const processedWebhooks = new Set<string>();
async function processWebhook(event: string, data: any) {
const webhookId = data.transactionId || data.cardId || data.card?.id;
if (processedWebhooks.has(webhookId)) {
console.log("Duplicate webhook ignored:", webhookId);
return;
}
processedWebhooks.add(webhookId);
await handleEvent(event, data);
}
Security
- Use HTTPS only - HTTP endpoints are not supported
- Verify webhook signatures (when enabled) using the
X-Cartevo-Signature header — see Verifying webhook signatures
- Validate request format - Ensure payload matches expected structure
- Implement rate limiting - Protect your endpoint from abuse
- IP whitelisting - Whitelist Cartevo IP addresses (when available)
Error Handling
Handle errors gracefully without exposing internal details:
app.post("/webhooks", async (req, res) => {
// Always respond with 200 first
res.status(200).json({ received: true });
try {
await processWebhook(req.body.event, req.body.data);
} catch (error) {
// Log error internally only
console.error("Webhook processing error:", {
event: req.body.event,
error: error.message,
});
// Alert monitoring system
}
});
Logging
Record important fields for supportability:
app.post("/webhooks", (req, res) => {
const { event, data } = req.body;
// Log webhook (use business identifiers; there is no webhook-id header)
console.log({
timestamp: new Date().toISOString(),
event,
transactionId: data.transactionId || data.transaction_id,
cardId: data.cardId || data.card_id || data.card?.id,
walletId: data.walletId || data.wallet_id,
});
res.status(200).json({ received: true });
processWebhook(event, data);
});
Sample Receiver Response
HTTP/1.1 200 OK
Content-Type: application/json
{"received": true}
Troubleshooting
| Issue | Solution |
|---|
| Receiving nothing | Verify the configured webhook URL and public reachability |
| 4xx errors | Your receiver rejected the request (auth/validation). Adjust your endpoint to accept the format above |
| 5xx errors | Your receiver errored; Cartevo will retry up to 3 times (4 total attempts) |
| Timeout errors | Respond within 10 seconds. Process webhooks asynchronously |
| Duplicate webhooks | Implement idempotency checks using transaction IDs |
Complete Event Reference
Payment Events (1)
payment.collect — Payment collection (pay-in) initiated.
Card Events (6)
card.created — Card successfully created.
card.verification.completed — Card account verified by a merchant ($0 hold).
card.fund — Card funded from a wallet.
card.withdraw — Money withdrawn from a card to a wallet.
card.withdraw.failed — Card withdrawal failed.
card.terminated — Card terminated (customer- or provider-initiated); remaining balance refunded.
Transaction Events (10)
transaction.authorization.created — Card payment authorized at a merchant.
transaction.authorization.declined — Card payment authorization declined.
transaction.preauthorization.created — Pre-authorization hold placed on a card.
transaction.reversal.completed — Authorization reversed (typically within 24h).
transaction.refund.completed — Refund processed (after settlement).
transaction.settlement.completed — Authorized transaction cleared.
transaction.funding.completed — Card funding transaction completed.
transaction.withdrawal.completed — Card withdrawal transaction completed.
transaction.crossborder.charged — Cross-border charge recorded against a card.
transaction.terminated — Termination-type transaction recorded.
Fee Events (2)
fee.payment_failure.charged — Failure-payment fee charged ($0.50).
fee.crossborder.charged — Cross-border fee charged (2.5% + $0.50).
Debt Events (1)
debt.recovery.pending — Fee debt created because the fee could not be deducted from the card or wallet.
Customer Events (1)
customer.created — Customer created.
Total: 21 webhook events