data object is the
resource snapshot (or {id, object} in thin mode). The lifecycle stage
lives on data.status. Dispatch on that, not the event name.
Envelope
sequence is a per-resource counter for discarding stale deliveries.
See Handle out-of-order deliveries.
It rides resource events and is absent on webhook.test,
message.attempt.exhausted, and partner application.* events.
ID shapes.
-
Meow-managed IDs (
entity_id,account_id,counterparty_id,virtual_account_id,subscription_id,delivery_id) are UUIDs. -
Resource IDs (
ach_transfer.id,wire_transfer.id, inbound transactionid,check_deposit.id,global_account_transfer.id) are opaque strings whose format varies by the underlying bank:- CRB / FirstBank:
deposit_inach_11mn5s777xgveb9,withdrawal_txc_15wp3bd309xenf6p,book_11n0b3vs9vy0ypw,interest_txc_15wp2ghq09qm3141. - Bridge global accounts:
bridge_va_inach_<uuid>(incoming ACH),bridge_va_iw_<uuid>(incoming wire),bridge_wallet_ext_ach_<uuid>(external ACH off-ramp),bridge_wallet_ext_wire_<uuid>(external wire),wallet_transfer_group_<uuid>/wallet_deposit_group_<uuid>(wallet send / receive). - Treasury Prime: TP’s own external IDs.
- CRB / FirstBank:
Onboarding events (
application.*, identity_verification.*) describe an
application’s lifecycle and go to whoever owns that application’s stream. If a
partner created it, they go to that partner’s subscription. If you onboarded
the business yourself through the API with a global key, they go to your own
entity subscription. You do not need a partner subscription to receive them.
So the two catalogs overlap on the onboarding events rather than being
disjoint. An entity subscription may name the rail events and the
onboarding events; a partner subscription may name only the onboarding events.
Listing an event a subscription could never receive returns a 400.
ach_transfer
status values: pending, processing, sent, returned, canceled, error.
Optional fields not shown in the sample: operation_request_id.
wire_transfer
Samestatus values as ach_transfer. Extra wire-only fields: counterparty_bank_name, purpose, imad (Fed reference), instructions.
book_transfer
A transfer between two accounts at the same bank. Emitted only for the debited (source) business, using the same outbound framing asach_transfer and wire_transfer, so the credited side does not get a copy. Internal legs Meow moves on your behalf (FX funding, insured cash sweep, core migrations) are suppressed.
status values: pending, sent, canceled, error. Book transfers use a narrower set than ach_transfer / wire_transfer: there is no processing, returned, or pending_approval leg.
Both sides are Meow accounts, so there are no counterparty routing details. to_entity_id is the business that was credited, including your own when you move money between two of your accounts. It is null when Meow cannot resolve the receiving account.
inbound_ach_transfer
status values: pending, posted, scheduled, failed, canceled, returned. Casing matches outbound (lowercase on the wire).
inbound_wire_transfer
Same shape as inbound ACH;object is inbound_wire_transfer.
check_deposit
Same shape as inbound ACH;object is check_deposit.
global_account_transfer
Activity on a global (virtual) account. Each activity is one-shot:funds_scheduled and funds_received for the same deposit share deposit_id but arrive as two separate events with different ids.
activity_type values: funds_scheduled, funds_received, payment_submitted, payment_processed, refund_in_flight, refunded, refund_failed.
currency is lowercase: usd, usdc, usdt, usdb, usdg, pyusd, dai, cash.
crypto_deposit
A stablecoin arriving at one of the entity’s deposit addresses. Both.created and .updated fire; status is the idempotency key, so one delivery emits per status transition (several vendor states collapse onto a single status value).
status values: pending, processing, completed, refunding, returned, canceled, failed.
destination values: global_account (funds stay in the Bridge global account) or bank_account (funds are converted to USD and wired to a Meow checking account). The fiat leg of a bank_account deposit is excluded from inbound_wire_transfer.* events — crypto_deposit.* is the only webhook signal for either destination.
currency is lowercase: usdc, usdt, usdb, usdg, pyusd, eurc, dai, cash, usdv, path_usd.
deposit_tx_hash is the on-chain transaction hash. Use it with the deposit_tx_hash query parameter on GET /accounts/{account_id}/transactions to look up the resulting bank transaction once status reaches completed.
No credited-amount field is included: the settlement amount is in the destination’s currency (USD for bank_account, the held stablecoin for global_account), which differs from currency and is not persisted with the deposit record.
card
A corporate card.card.created fires when a card is issued; card.updated fires on every subsequent change. Dispatch on data.status, not the event type — every state change, including freeze and unfreeze, arrives as card.updated.
status values: pending (issuer is provisioning the card), active, suspended (frozen or under a fraud hold), closed, failed.
last_four reads **** while the card is still provisioning.
spending_restriction is set when the card is restricted to or blocked from a specific merchant list. allowed_categories narrows the card to specific MCC categories; null means every category is allowed.
account
A Meow deposit account.account.created fires when the account is live and addressable on GET /accounts. For Treasury Prime that is when the bank confirms the application, later than the POST /accounts call. account.updated fires on status changes, including closes.
status values: OPEN, PENDINGOPEN, PENDINGCLOSE, CLOSED, RESTRICTED, DELINQUENT.
reference_id is the value you sent on POST /accounts. It is how you match this event back to the request that opened the account, which matters most on the products that open in the background, where the create response carries no account_id. It is null if you did not send one.
Balances are not included. They move independently of the account itself. Read them from GET /accounts/{account_id}.
info_request
A reviewer’s request for more documents or answers, raised against a business that has already submitted.info_request.created fires when the request is
raised. info_request.updated fires each time the outstanding set changes: a
document lands, the questions are answered, and again when the request is
satisfied.
outstanding is everything the request is still waiting on, documents and
questions alike. required_proof_types is the document half of that, as
proof_type values the upload endpoints accept. completed_at is what says
the request is done. It is null while anything is left.
Fetch the request’s form with
GET /entities/{entity_id}/info-requests/{request_id}/schema to see exactly
what to collect. See the onboarding guide for the full
flow.
Expiry emits no event. A request lapses when its
expires_at passes, and
nothing runs at that moment. Read expires_at and time it out yourself.onboarding_consent
The agreements the business has to accept, tracked against the consent record that backsconsent_url. onboarding_consent.updated fires when they first
become owed at submission, when the representative opens the form, and on each
item they accept.
remaining_items is what is still owed and consented_items is what has been
accepted. status moves pending to viewed to completed; completed_at
is set once nothing remains.
The event at submission is what tells you the agreements are owed at all. Every
later event is driven by the representative acting on the form, so a business
whose link is never opened produces no further events. Until remaining_items
is empty, POST /accounts returns 403.
This family has no
.created. Unlike the other resources, the consent record
reports every stage through onboarding_consent.updated, including the first
event at submission. Dispatch on status and remaining_items, not on the
event name.webhook.test
Triggered manually viaPOST /webhooks/subscriptions/{id}/test. Always sent in full (the thin mode falls through because there’s no id to GET).
message.attempt.exhausted
Fires when a delivery hits 10 failed attempts. The subscription is auto-disabled (disabled_reason=retry_exhausted). Use this to page an on-call. last_response_status is null if every attempt failed before getting an HTTP response (timeout, DNS, TLS).
application
Delivered to whoever owns the application’s stream: the partner that created it, or, for an API self-serve onboarding opened with a global key, the onboarded business’s own entity subscription. Each event reports an onboarding application reaching a new status; the event name anddata.status always
match. application_id is the application identifier (the KYB info public id);
entity_id is the onboarded business, present on every event including
application.created. previous_status is null only on application.created.
status values: pending_document_upload, pending_user_action,
under_review, submitted, approved, rejected. Note submitted sits
later in the lifecycle than under_review: under_review means KYB review
is pending, submitted means KYB approved but the account is not yet active.
Unlike the rail events, application.* events carry no sequence and are
always delivered as a full snapshot (partner subscriptions don’t support
thin mode).
identity_verification
Reports one representative’s identity-verification status on an onboarding application. Delivered to the same owner asapplication.*: the partner that
created the application, or, for an API self-serve onboarding opened with a
global key, the onboarded business’s own entity subscription.
This is a separate family from the application-level application.* events; a
subscriber can take one without the other.
status is always action_required, approved, or rejected, mirroring
the event name. previous_status may additionally be pending, and is null
on the first notification.
Only approved is final. action_required means the representative has to
verify again (their verification expired or was canceled) and can legitimately
repeat across attempts, and a rejected representative stays under
reconciliation, so either may be followed by further events if they verify
again.
The payload carries normalized state only, never the underlying reason: no
PEP, watchlist, or vendor failure detail is included. representative_id is
the stable identifier; representative_email is the correlation key you
submitted.
Like application.*, these carry no sequence and are always a full
snapshot.