Infracard

Webhooks

Receive real-time notifications for card events

Overview

Webhooks let you receive real-time HTTP notifications when events occur in your Infracard account. Instead of polling the API, Infracard sends POST requests to your configured endpoint when events happen.

Webhook endpoints are configured during merchant onboarding — there are no self-serve management endpoints. Contact your account manager to update your webhook URL or event subscriptions.

Event Types

EventDescription
card.activatedA card was successfully activated
card.freezeCard freeze operation completed or failed (check status)
card.unfreezeCard unfreeze operation completed or failed (check status)
card.depositCard deposit processing, completed, or failed (check status)
card.withdrawCard withdrawal completed or failed (check status)
card.auth_transactionAn authorization transaction was processed on a card
card.3dsA 3D Secure challenge was triggered
card_holder.status_changedA card holder's KYC/status changed
merchant.balance_creditedMerchant balance was credited

Payload Format

The request body contains the raw event data with no wrapper. Event metadata is sent via HTTP headers:

HeaderDescription
X-Webhook-IdUnique delivery ID
X-Event-TypeEvent type (e.g. card.activated)
X-TimestampUnix milliseconds when the event was dispatched
X-Webhook-SignatureRSA-SHA256 signature of the request body

Example payload for a card.activated event:

{
  "providerOrderId": "WO2025022100001",
  "orderNo": "ORD-20250221-0001",
  "merchantOrderNo": "MY-REF-001",
  "cardId": "card_abc123",
  "loadAmount": "100.00",
  "issuanceFee": "2.50",
  "depositFee": "0.00",
  "providerId": "wasabi",
  "providerDepositFee": "0.00"
}

Verifying Signatures

Infracard signs every webhook payload using RSA-SHA256 with the platform's private key. You receive the corresponding public key during onboarding.

To verify a delivery, check the X-Webhook-Signature header against the raw request body using the public key:

import crypto from 'crypto'

const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\n${process.env.INFRACARD_PUBLIC_KEY}\n-----END PUBLIC KEY-----`

function verifyWebhookSignature(
  rawBody: string,
  signature: string,
): boolean {
  const verifier = crypto.createVerify('RSA-SHA256')
  verifier.update(rawBody)
  return verifier.verify(PUBLIC_KEY, signature, 'base64')
}

Important: Verify against the raw request body string, not a re-serialized object. Re-serializing may change key ordering or whitespace, which will invalidate the signature.

Retry Policy

If your endpoint returns a non-2xx status code or the request times out (30 s), Infracard retries the delivery with the following backoff schedule:

AttemptDelay after failure
1st retry5 seconds
2nd retry30 seconds
3rd retry2 minutes
4th retry10 minutes
5th retry30 minutes
6th retry1 hour
7th retry2 hours
8th retry4 hours

After 9 total attempts (1 initial + 8 retries), the delivery is marked as failed and no further retries are made.

Best Practices

  • Respond quickly. Return a 200 status code as soon as you receive the webhook, then process the event asynchronously. Infracard will time out after 30 seconds.
  • Handle duplicates. Use the X-Webhook-Id header to deduplicate deliveries. The same event may be delivered more than once during retries.
  • Verify signatures. Always validate the X-Webhook-Signature header before processing the payload to ensure the request originated from Infracard.

Event Reference

Card Lifecycle

card.activated

Fires after the card provider confirms card creation. The card is live and usable. Funds have been settled from the merchant balance.

FieldTypeDescription
providerOrderIdstringProvider's order identifier
orderNostringInfracard order number
merchantOrderNostringYour order reference passed at issuance
cardIdstringThe new card's ID
loadAmountstringInitial card balance loaded
issuanceFeestringFee charged for card issuance
depositFeestringFee charged for the initial deposit
providerIdstringCard provider identifier
providerDepositFeestringFee charged by the provider for the deposit
{
  "providerOrderId": "WO2025022100001",
  "orderNo": "ORD-20250221-0001",
  "merchantOrderNo": "MY-REF-001",
  "cardId": "card_abc123",
  "loadAmount": "100.00",
  "issuanceFee": "2.50",
  "depositFee": "0.00",
  "providerId": "wasabi",
  "providerDepositFee": "0.00"
}

card.freeze

Async result of a card freeze operation. On success, the card is now frozen. On fail, the card has reverted to its prior state.

FieldTypeDescription
statusstringsuccess or fail
cardIdstringThe card's ID

Success:

{
  "status": "success",
  "cardId": "card_abc123"
}

Failure:

{
  "status": "fail",
  "cardId": "card_abc123"
}

card.unfreeze

Async result of a card unfreeze operation. On success, the card is active again. On fail, the card remains frozen.

FieldTypeDescription
statusstringsuccess or fail
cardIdstringThe card's ID

Success:

{
  "status": "success",
  "cardId": "card_abc123"
}

Failure:

{
  "status": "fail",
  "cardId": "card_abc123"
}

Card Funding

card.deposit

Result of a card top-up. On processing, the order has been accepted and funds are frozen from the merchant balance. On success, the card balance has been loaded and merchant funds are settled permanently. On fail, frozen merchant funds are returned and the card balance is unchanged.

FieldTypeStatusDescription
statusstringbothprocessing, success, or fail
orderNostringbothInfracard order number
merchantOrderNostringbothYour order reference passed at deposit
amountstringsuccessAmount deposited to the card
depositFeestringsuccessFee charged for the deposit
providerDepositFeestringsuccessFee charged by the provider for the deposit
issuanceFeestring | nullsuccessFee charged for card issuance (null when the deposit is not part of a card issuance)
remarkstring | nullfailRejection reason, if provided

Success:

{
  "status": "success",
  "orderNo": "ORD-20250221-0005",
  "merchantOrderNo": "idem_dep456",
  "amount": "50.00",
  "depositFee": "1.25",
  "providerDepositFee": "0.50",
  "issuanceFee": null
}

Success (with issuance):

{
  "status": "success",
  "orderNo": "ORD-20250221-0005",
  "merchantOrderNo": "idem_dep456",
  "amount": "50.00",
  "depositFee": "1.25",
  "providerDepositFee": "0.50",
  "issuanceFee": "2.50"
}

Processing:

{
  "status": "processing",
  "orderNo": "ORD-20250221-0004",
  "merchantOrderNo": "idem_dep456"
}

Failure:

{
  "status": "fail",
  "orderNo": "ORD-20250221-0006",
  "merchantOrderNo": "idem_dep789",
  "remark": "Insufficient provider limits"
}

card.withdraw

Result of a card withdrawal. On success, funds were reclaimed from the card back to the merchant balance. On fail, the card balance is unchanged and no funds are returned.

FieldTypeStatusDescription
statusstringbothsuccess or fail
providerOrderIdstringbothProvider's order identifier
idempotencyKeystringbothThe idempotency key from the original request
providerCardIdstringsuccessProvider's card identifier
amountstringsuccessAmount withdrawn from the card
remarkstring | nullfailRejection reason, if provided

Success:

{
  "status": "success",
  "providerOrderId": "WO2025022100007",
  "idempotencyKey": "idem_wd001",
  "providerCardId": "PC-987654",
  "amount": "25.00"
}

Failure:

{
  "status": "fail",
  "providerOrderId": "WO2025022100008",
  "idempotencyKey": "idem_wd002",
  "remark": null
}

Transactions

card.auth_transaction

Fires every time the card is used — purchases, refunds, reversals, verifications, and fees. Use this for real-time spending visibility and reconciliation. Transaction status cycles through: PENDINGCOMPLETED / DECLINED / SETTLED.

FieldTypeDescription
providerCardIdstringProvider's card identifier
tradeNostringProvider's transaction identifier
typestringPURCHASE, REFUND, REVERSAL, VERIFICATION, or FEE
statusstringPENDING, COMPLETED, DECLINED, or SETTLED
amountstringTransaction amount
merchantNamestringName of the merchant where the card was used
feestringTransaction fee
crossBorderFeestringCross-border fee, if applicable
settleAmountstring | nullFinal settlement amount (present once settled)
accountingobject[]Debit/credit accounting entries (see below)
strategyVersionnumberFee strategy version used for this transaction

Each entry in the accounting array:

FieldTypeDescription
typestringdebit or credit
amountstringEntry amount
referenceIdstringOperation type (e.g. card-purchase)
externalIdstringProvider's transaction identifier
{
  "providerCardId": "PC-987654",
  "tradeNo": "TXN-2025022100001",
  "type": "PURCHASE",
  "status": "PENDING",
  "amount": "42.99",
  "merchantName": "Coffee Shop",
  "fee": "0.43",
  "crossBorderFee": "0.00",
  "settleAmount": null,
  "accounting": [
    {
      "type": "debit",
      "amount": "42.99",
      "referenceId": "card-purchase",
      "externalId": "TXN-2025022100001"
    },
    {
      "type": "debit",
      "amount": "0.43",
      "referenceId": "card-purchase-fee",
      "externalId": "TXN-2025022100001"
    }
  ],
  "strategyVersion": 1
}

card.3ds

A 3D Secure challenge was triggered during an online purchase. You must deliver the OTP code or redirect URL to the cardholder within approximately 60 seconds. This event does not change any internal state — it is a pass-through from the card provider.

FieldTypeDescription
providerCardIdstringProvider's card identifier
tradeNostringProvider's transaction identifier
typestringthird_3ds_otp (OTP code) or auth_url (redirect URL)
decryptedValuestringThe OTP code or redirect URL
{
  "providerCardId": "PC-987654",
  "tradeNo": "TXN-2025022100002",
  "type": "third_3ds_otp",
  "decryptedValue": "482901"
}

Card Holder

card_holder.status_changed

The card holder's KYC review status changed. A status of approved means the holder can now issue cards. rejected means KYC failed. under_review means manual review is in progress.

FieldTypeDescription
providerHolderIdstringProvider's card holder identifier
statusstringNew KYC status (e.g. approved, rejected, under_review)
{
  "providerHolderId": "PH-123456",
  "status": "approved"
}

Merchant

merchant.balance_credited

The merchant balance was topped up via an admin credit or an approved crypto deposit. Use this event for reconciliation.

FieldTypeDescription
amountstringAmount credited
newBalancenumberUpdated merchant balance after the credit
{
  "amount": "1000.00",
  "newBalance": 5250.75
}