Event Types

Available Events

Event NameTriggerContentSample Payload
transactionmessage.createdWhenever a new Transaction Message is registered in the Astrada systemA complete understanding of the created Transaction Message objectSee here
transaction.createdWhenever a new Transaction is created in the Astrada systemReferences to the transaction object and its related entitiesSee here
transaction.updatedWhenever a Transaction is updated in the Astrada systemReferences to the updated transaction object and its related entitiesSee here
banklink.completedWhenever a bank-link enrollment completesThe completed bank link and the bank accounts discovered under itSee here
bankaccount.state_changedWhenever a linked bank account's connection state changesThe bank account with its new and previous state, and any re-auth reasonSee here
banktransaction.createdWhenever a bank transaction is synced from a linked bank accountThe created bank transactionSee here
transaction.match.createdWhenever a bank transaction is matched to a card transactionThe match with its confidence, scoring reasons, and both matched sidesSee here
cardsubscription.createdWhenever a Card Subscription is created in the Astrada systemReference to the created card subscriptionSee here
cardsubscription.updatedWhenever a Card Subscription is updated in the Astrada systemReference to the updated card subscriptionSee here
networkbulkfeed.statechangedWhenever a Network Bulk Feed changes stateReference to the network bulk feed and the new and old statesSee here
enrichment.merchant.createdWhenever a Transaction Message is enriched with Merchant dataA complete understanding of the created Merchant EnrichmentSee here🧪

🧪 Experimental Feature — behavior may change.

Sample Payloads

Alongside the payload that is sent in HTTP request body (in JSON format), an HTTP header (webhook-event-type) is also present that allows to infer the event type.

transactionmessage.created

Payload is identical to the GET Transaction Message endpoint

transaction.created

Payload consists of links to the created transaction and its related entities.

{
  "_links": {
    "self": {
      "href": "/transactions/884820d4-1b11-4dfd-ab83-988f754712da"
    },
    "subaccount": {
      "href": "/subaccounts/c6d5e036-361e-4773-a514-b9496cf2d2b5"
    },
    "card": {
      "href": "/cards/4d1ff59f-4286-4209-9662-92e174193562"
    },
    "messages": [
      {
        "href": "/transaction-messages/f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4"
      }
    ]
  },
  "acceptor": {
    "city": "LONDON",
    "country": "GBR",
    "mcc": "5734",
    "state": "LND"
  },
  "cardId": "4d1ff59f-4286-4209-9662-92e174193562",
  "cardholderBillingCurrency": "GBP",
  "cardholderBillingHoldAmount": 0,
  "cardholderBillingSettledAmount": 0.81,
  "createdAt": "2024-05-01T06:41:43.810Z",
  "descriptor": "Uber",
  "id": "884820d4-1b11-4dfd-ab83-988f754712da",
  "network": "MASTERCARD",
  "status": "SETTLED",
  "subaccountId": "c6d5e036-361e-4773-a514-b9496cf2d2b5",
  "transactionCurrency": "USD",
  "transactionHoldAmount": 0,
  "transactionSettledAmount": 1,
  "transactionType": "DEBIT_01",
  "updatedAt": "2024-05-02T08:41:43.810Z"
}

Augmenting transaction.created with a projection of transaction messages data

Transaction message data is included as part of the transaction.created webhook by default. An array containing all correlated messages is added to the transaction aggregate payload inside the _embedded field. Example:

{
  "_embedded": {
    "messages": [
      {
        "_links": {
          "self": {
            "href": "/transaction-messages/f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4"
          }
        },
        "approvalCode": "537254",
        "cardholderBillingAmount": 1.18,
        "cardholderBillingCurrency": "GBP",
        "dateTime": "2024-04-24T13:39:45",
        "id": "f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4",
        "messageType": "FINL_ADVC",
        "network": "MASTERCARD",
        "result": "APPROVED",
        "transactionAmount": 1.45,
        "transactionCurrency": "USD",
        "transactionReference": "IWVQ22_2024-04-24"
      }
    ]
  }
}

This expanded payload is enabled by default. If your integration cannot accept the _embedded projection, reach out to your Astrada Account Manager or [email protected] to have it disabled.

transaction.updated

Payload consists of links to the updated transaction and its related entities.

{
  "_links": {
    "self": {
      "href": "/transactions/884820d4-1b11-4dfd-ab83-988f754712da"
    },
    "subaccount": {
      "href": "/subaccounts/c6d5e036-361e-4773-a514-b9496cf2d2b5"
    },
    "card": {
      "href": "/cards/4d1ff59f-4286-4209-9662-92e174193562"
    },
    "messages": [
      {
        "href": "/transaction-messages/f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4"
      },
      {
        "href": "/transaction-messages/934f8701-53e3-4a2b-a000-6bb52195d2ea"
      }
    ]
  },
  "acceptor": {
    "city": "LONDON",
    "country": "GBR",
    "mcc": "5734",
    "state": "LND"
  },
  "cardId": "4d1ff59f-4286-4209-9662-92e174193562",
  "cardholderBillingCurrency": "GBP",
  "cardholderBillingHoldAmount": 0,
  "cardholderBillingSettledAmount": 0.81,
  "createdAt": "2024-05-01T06:41:43.810Z",
  "descriptor": "Uber",
  "id": "884820d4-1b11-4dfd-ab83-988f754712da",
  "network": "MASTERCARD",
  "status": "SETTLED",
  "subaccountId": "c6d5e036-361e-4773-a514-b9496cf2d2b5",
  "transactionCurrency": "USD",
  "transactionHoldAmount": 0,
  "transactionSettledAmount": 1,
  "transactionType": "DEBIT_01",
  "updatedAt": "2024-05-02T08:41:43.810Z"
}

Augmenting transaction.updated with a projection of transaction messages data

Transaction message data is included as part of the transaction.updated webhook by default. An array containing all correlated messages is added to the transaction aggregate payload inside the _embedded field. Example:

{
  "_embedded": {
    "messages": [
      {
        "_links": {
          "self": {
            "href": "/transaction-messages/f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4"
          }
        },
        "approvalCode": "537254",
        "cardholderBillingAmount": 1.18,
        "cardholderBillingCurrency": "GBP",
        "dateTime": "2024-04-24T13:39:45",
        "id": "f4b24a0a-6a37-4ce3-8845-ddf0b604a9b4",
        "messageType": "FINL_ADVC",
        "network": "MASTERCARD",
        "result": "APPROVED",
        "transactionAmount": 1.45,
        "transactionCurrency": "USD",
        "transactionReference": "IWVQ22_2024-04-24"
      }
    ]
  }
}

This expanded payload is enabled by default. If your integration cannot accept the _embedded projection, reach out to your Astrada Account Manager or [email protected] to have it disabled.

Bank-sourced activity (bank linking)

When a bank account is linked, bank-observed money movement rides the SAME events documented above — there are no new event types or payload shapes to integrate. Three things are worth knowing:

1. Bank-only transactions. A bank movement with no card counterpart (payroll, transfers, fees, FX markup — and, on a card-less bank link, everything) arrives as a transactionmessage.created carrying a synthetic FINL_ADVC, followed by a transaction.created for the new SETTLED aggregate. The universal markers are: no approvalCode, a bank_-prefixed transactionReference, and a bankData block. A bank-only movement always carries network: "OPEN_BANKING" — it never adopts a card network. On a card-less account it also carries cardId: null (_links.card omitted); on an account with linked cards it is attributed to the account's oldest linked card and carries that card's cardId (for feed grouping only — the network stays "OPEN_BANKING").

2. Earlier settlement. When a bank posting matches one of your card transactions with high confidence, the transaction settles early: a bank-sourced FINL_ADVC (inheriting the auth's transactionReference, approvalCode, and network) and a transaction.updated flipping PENDING→SETTLED — typically hours after the swipe instead of days. When the card network's own clearing arrives later, the settled amounts may revise once more (tips, FX): the network remains the financial authority. Amount revision on transaction.updated is expected behavior, not an error.

3. Bank-first, card-later. If the bank movement arrived first as a standalone transaction and card data shows up later, the movement is re-settled onto the card transaction and the standalone's transaction.updated revises its settled amounts to 0 (status stays SETTLED). No new field or status to handle — consumers that already process amount revisions get this for free. Re-matching of late card data runs on a scheduled cadence (tight in the first hours, then progressively less frequent across the 14-day match window), and the card transaction's settlement and the standalone's netting revision ride independent stream partitions — they can arrive in either order. Key state by bankData.bankTransactionId and treat each event as an idempotent upsert, and both properties are harmless.

Linking the surfaces. bankData.bankTransactionId (on bank-sourced transactionmessage.created payloads and the _embedded.messages[] projection) equals banktransaction.created.id and transaction.match.created.matches[].id, and resolves via GET /bank-transactions/{subaccountId}/{id} — one join key across every bank-data surface, no extra REST calls needed to correlate push events.

A bank-sourced embedded message carries the join key in its bankData block (deliberately slim — the bank's merchant string, dates and amounts already map into the message's canonical fields; personalFinanceCategory is the one bank-only datum with no card-side equivalent):

{
  "bankData": {
    "provider": "plaid",
    "bankTransactionId": "7f2a9c4e-3b1d-4e8f-a5c7-6d0e2f9b8a3c",
    "personalFinanceCategory": {
      "primary": "FOOD_AND_DRINK",
      "detailed": "FOOD_AND_DRINK_RESTAURANT"
    }
  }
}

That bankTransactionId is the id of the corresponding banktransaction.created event (and matches[].id on transaction.match.created), so you can stitch the bank-feed events and this unified transaction into one record with no extra call.

Dedicated bank events. Beyond the transaction.* feed above, the banking service emits the four events below directly, and they can be subscribed to independently — the bank-linking lifecycle (banklink.completed, bankaccount.state_changed) and the bank-side records (banktransaction.created, transaction.match.created). They share the bank-transaction id join key described above.

banklink.completed

Sent when a bank-link enrollment finishes — via the manual PATCH /bank-links/{bankLinkId} completion or the hosted-link flow (Plaid SESSION_FINISHED plus the polling fallback). The payload carries the completed bankLinkId and the bank accounts discovered under it, so a push-only consumer can react to a new connection without polling GET /bank-links.

{
  "bankLinkId": "enrollment_792dcb7d",
  "bankAccounts": [
    {
      "id": "3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c",
      "name": "Checking"
    }
  ]
}

bankaccount.state_changed

Sent whenever a linked bank account's connection state actually changes — to auth_required (with a reason and, when known, an expiresAt), to disconnected, or back to active on recovery. Integrators can prompt the end user to re-authenticate — and stop prompting — without polling GET /bank-accounts. state is one of active, auth_required, or disconnected; reason and expiresAt are null unless applicable.

{
  "bankAccountId": "3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c",
  "state": "auth_required",
  "previousState": "active",
  "reason": "consent_expiring",
  "expiresAt": "2026-07-09T00:00:00.000Z"
}

banktransaction.created

Sent when a bank transaction is synced from a linked account (via Plaid sync). Its id is the bank-transaction identifier that threads through every bank-data surface — it equals transaction.match.created.matches[].id and the bankData.bankTransactionId on the card feed, and resolves via GET /bank-transactions/{subaccountId}/{id}. amount is always positive — direction is carried by transactionType (debit or credit). category is the primary personal-finance category (or null) — note the REST GET /bank-transactions resource exposes category as an array of provider categories instead; merchantName may be null.

{
  "id": "7f2a9c4e-3b1d-4e8f-a5c7-6d0e2f9b8a3c",
  "bankAccountId": "3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c",
  "bankAccountName": "Checking",
  "date": "2025-10-15",
  "amount": 42.5,
  "currency": "USD",
  "description": "UBER TRIP",
  "merchantName": "Uber",
  "category": "Travel",
  "pending": false,
  "transactionType": "debit"
}

transaction.match.created

Sent when the matching engine links a bank transaction to one of your card transactions. The payload includes the match's own matchId (address it at GET /transaction-matches/{subaccountId}/{matchId}; the REST resource exposes the same value as its top-level id), the confidence (HIGH ≥ 0.70, MEDIUM ≥ 0.50, LOW ≥ 0.20) and numeric score, the per-factor reasons behind the score, a summary of the matched card transaction, and the matched bank transaction(s) under matches[]. Each matches[].id is the bank-transaction id — the shared join key across the bank-data surfaces.

{
  "matchId": "b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e",
  "confidence": "HIGH",
  "score": 0.88,
  "cardTransaction": {
    "id": "9c8b7a6d-5e4f-3c2b-1a0d-9e8f7c6b5a4d",
    "cardId": "5dec2c49-0aa5-4683-a317-427eb5d115f3",
    "date": "2025-10-15",
    "amount": 42.5,
    "currency": "USD",
    "descriptor": "UBER   *TRIP",
    "source": "Card"
  },
  "reasons": [
    {
      "type": "Amount",
      "score": 1,
      "cardValue": 42.5,
      "bankValue": 42.5,
      "diff": 0,
      "message": "Exact match"
    },
    {
      "type": "Date",
      "score": 1,
      "cardValue": "2025-10-15",
      "bankValue": "2025-10-15",
      "diff": 0,
      "message": "Exact match"
    },
    {
      "type": "Merchant",
      "score": 0.88,
      "cardValue": "UBER   *TRIP",
      "bankValue": "Uber",
      "diff": 12,
      "message": "88% similarity"
    }
  ],
  "matches": [
    {
      "id": "7f2a9c4e-3b1d-4e8f-a5c7-6d0e2f9b8a3c",
      "bankAccountId": "3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c",
      "bankAccountName": "Checking",
      "date": "2025-10-15",
      "amount": 42.5,
      "currency": "USD",
      "source": "Plaid",
      "description": "UBER TRIP"
    }
  ]
}

cardsubscription.created

Payload consists of links to the created subscription.

For cardholder-single enrollments, networkBulkFeedId is null and the networkBulkFeed link is not present:

{
  "_links": {
    "card": {
      "href": "/cards/94b9b0ce-5775-470d-855e-0c0d0e72b0ea"
    },
    "self": {
      "href": "/card-subscriptions/aadf6c89-0356-4d94-8fa8-b5465077a0fb"
    }
  },
  "cardId": "94b9b0ce-5775-470d-855e-0c0d0e72b0ea",
  "createdAt": "2024-09-02T09:42:39.678Z",
  "customerReferenceId": null,
  "effectiveDate": "2024-09-02T09:42:39.677Z",
  "enrollmentType": "cardholder-single",
  "expirationDate": "2025-09-02T09:42:43.270Z",
  "id": "aadf6c89-0356-4d94-8fa8-b5465077a0fb",
  "networkBulkFeedId": null,
  "state": "reqSCA",
  "subaccountId": "6103874b-248d-4825-af88-a0d24dd9b123",
  "updatedAt": "2024-09-02T09:42:43.576Z"
}

For network-bulk enrollments, networkBulkFeedId and the networkBulkFeed link are included:

{
  "_links": {
    "card": {
      "href": "/cards/94b9b0ce-5775-470d-855e-0c0d0e72b0ea"
    },
    "networkBulkFeed": {
      "href": "/network-bulk-feeds/5ccc9922-e763-4492-b693-b6a922d96049"
    },
    "self": {
      "href": "/card-subscriptions/aadf6c89-0356-4d94-8fa8-b5465077a0fb"
    }
  },
  "cardId": "94b9b0ce-5775-470d-855e-0c0d0e72b0ea",
  "createdAt": "2024-09-02T09:42:39.678Z",
  "customerReferenceId": null,
  "effectiveDate": "2024-09-02T09:42:39.677Z",
  "enrollmentType": "network-bulk",
  "expirationDate": "2025-09-02T09:42:43.270Z",
  "id": "aadf6c89-0356-4d94-8fa8-b5465077a0fb",
  "networkBulkFeedId": "5ccc9922-e763-4492-b693-b6a922d96049",
  "state": "active",
  "subaccountId": "6103874b-248d-4825-af88-a0d24dd9b123",
  "updatedAt": "2024-09-02T09:42:43.576Z"
}

cardsubscription.updated

Payload consists of links to the updated subscription.

For cardholder-single enrollments:

{
  "_links": {
    "card": {
      "href": "/cards/94b9b0ce-5775-470d-855e-0c0d0e72b0ea"
    },
    "self": {
      "href": "/card-subscriptions/aadf6c89-0356-4d94-8fa8-b5465077a0fb"
    }
  },
  "cardId": "94b9b0ce-5775-470d-855e-0c0d0e72b0ea",
  "createdAt": "2024-09-02T09:42:39.678Z",
  "customerReferenceId": null,
  "effectiveDate": "2024-09-02T09:42:39.677Z",
  "enrollmentType": "cardholder-single",
  "expirationDate": "2025-09-02T09:42:43.270Z",
  "id": "aadf6c89-0356-4d94-8fa8-b5465077a0fb",
  "networkBulkFeedId": null,
  "state": "active",
  "subaccountId": "6103874b-248d-4825-af88-a0d24dd9b123",
  "updatedAt": "2024-09-02T10:01:44.176Z"
}

For network-bulk enrollments:

{
  "_links": {
    "card": {
      "href": "/cards/94b9b0ce-5775-470d-855e-0c0d0e72b0ea"
    },
    "networkBulkFeed": {
      "href": "/network-bulk-feeds/5ccc9922-e763-4492-b693-b6a922d96049"
    },
    "self": {
      "href": "/card-subscriptions/aadf6c89-0356-4d94-8fa8-b5465077a0fb"
    }
  },
  "cardId": "94b9b0ce-5775-470d-855e-0c0d0e72b0ea",
  "createdAt": "2024-09-02T09:42:39.678Z",
  "customerReferenceId": null,
  "effectiveDate": "2024-09-02T09:42:39.677Z",
  "enrollmentType": "network-bulk",
  "expirationDate": "2025-09-02T09:42:43.270Z",
  "id": "aadf6c89-0356-4d94-8fa8-b5465077a0fb",
  "networkBulkFeedId": "5ccc9922-e763-4492-b693-b6a922d96049",
  "state": "active",
  "subaccountId": "6103874b-248d-4825-af88-a0d24dd9b123",
  "updatedAt": "2024-09-02T10:01:44.176Z"
}

networkbulkfeed.statechanged


Webhook payload consists of a link to the related entity and the new and old states.

{
  "_links": {
    "self": {
      "href": "/network-bulk-feeds/884820d4-1b11-4dfd-ab83-988f754712da"
    }
  },
  "createdAt": "2024-05-01T06:41:43.810Z",
  "id": "884820d4-1b11-4dfd-ab83-988f754712da",
  "network": "MASTERCARD",
  "networkReference": "G234621",
  "newState": "active",
  "oldState": "submitted",
  "subaccountId": "c6d5e036-361e-4773-a514-b9496cf2d2b5",
  "updatedAt": "2024-05-02T08:41:43.810Z"
}

When a bulk feed transitions to the failed state, an errorReason field is included in the payload. This currently only applies to VISA bulk feeds.

{
  "_links": {
    "self": {
      "href": "/network-bulk-feeds/a23bb1e5-2bb9-4472-be8b-a500e21c8a42"
    }
  },
  "createdAt": "2026-04-08T22:54:32.111Z",
  "errorReason": "A bad request error occurred while requesting starter data: \"789452INVALID: Your Company ID is not a numeric value. Please provide a valid company ID!; No records found for the given inputs. Please provide valid inputs!\"",
  "id": "a23bb1e5-2bb9-4472-be8b-a500e21c8a42",
  "network": "VISA",
  "networkReference": "1_1_9999_789452INVALID",
  "newState": "failed",
  "oldState": "submitted",
  "subaccountId": "2f394ae7-5eef-4dfa-b3c3-0e973ae2ec51",
  "updatedAt": "2026-04-08T22:54:32.111Z"
}

When a bulk feed was created with expectedCardCount, the value is included on every webhook payload for that feed. Absent when the feed was created without it.

{
  "_links": {
    "self": {
      "href": "/network-bulk-feeds/884820d4-1b11-4dfd-ab83-988f754712da"
    }
  },
  "createdAt": "2024-05-01T06:41:43.810Z",
  "id": "884820d4-1b11-4dfd-ab83-988f754712da",
  "network": "MASTERCARD",
  "networkReference": "G234621",
  "newState": "active",
  "expectedCardCount": 5000,
  "oldState": "submitted",
  "subaccountId": "c6d5e036-361e-4773-a514-b9496cf2d2b5",
  "updatedAt": "2024-05-02T08:41:43.810Z"
}

enrichment.merchant.created

{
  "_links": {
    "message": {
      "href": "/transaction-messages/884820d4-1b11-4dfd-ab83-988f754712da"
    },
    "merchant": {
      "href": "https://www.amazon.com",
      "title": "Amazon"
    },
    "merchant-logo": {
      "href": "https://static.v2.spadeapi.com/logos/5f35110e8de74f9cadc6b28bf87dd5b6/light.png",
      "type": "image/png",
      "title": "Amazon logo"
    }
  },
  "id": "6fb8303a-3a91-41d1-a56d-5056cc7e84a9",
  "createdAt": "2025-10-20T17:38:317Z",
  "merchant": {
    "name": "Amazon",
    "category": "Online Marketplace"
  },
  "location": {
    "address": "1234 W 5th Ave Suite 100",
    "city": "New York",
    "state": "NY",
    "country": "USA",
    "postalCode": "10001",
    "phoneNumber": "+18664862360"
  }
}