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,counterparty_id,virtual_account_id,subscription_id,delivery_id) are UUIDs. Account IDs are opaque strings such ascash_account_<uuid>orbridge_wallet_<uuid>. -
Resource IDs (
ach_transfer.id,wire_transfer.id, inbound transactionid,check_deposit.id,global_account_transfer.id,crypto_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_transfer
An inbound deposit or outbound crypto send. The first observed state emitscrypto_transfer.created. Later status changes emit crypto_transfer.updated. Several provider states can map to one public status, so not every provider callback produces an event.
direction is inbound or outbound.
status moves through:
A reversed transfer reports
refunding first and returned only once the refund
settles, so treat refunding as in-flight and wait for returned before
reconciling the money as returned. Several provider states collapse onto
refunding, so you may receive it once for a sequence of provider callbacks.
amount and currency describe the cryptocurrency transferred on chain. For a send funded with dollars, amount is the recipient amount after fees, not the dollar amount debited from the source account.
For inbound transfers, destination is global_account or bank_account. source_tx_hash and source_address identify the on-chain source when available. Use source_tx_hash as the deposit_tx_hash query value on GET /accounts/{account_id}/transactions to reconcile the resulting account transaction. The fiat leg of a bank_account deposit does not emit inbound_wire_transfer.*.
For outbound transfers, destination and all source fields are null. destination_address, destination_tx_hash, and destination_address_nickname describe the recipient. destination_tx_hash stays null until Bridge reports it. Outbound events cover global-account sends and direct bank-funded sends. Legacy bank-funded static-memo sends continue to use wire webhooks.
account_id identifies the account that sends or receives the funds. Subscriptions are entity-scoped, so use this field to route the event.
Inbound example
Outbound example
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.
bill
A bill you owe a vendor. Drafts send no events: a bill created with the API, in the dashboard, from an emailed invoice, or from a recurring schedule starts as a draft, and you hear about it when it is first submitted. That first submission sendsbill.created. After it, every status move sends bill.updated: approved, rejected, scheduled, paid, failed, canceled, or moved back to draft. Dispatch on data.status, not the event type.
You get one event per status move, carrying the whole bill as it stands after it. A submission that approval rules approve straight away is one move, so it sends one bill.created with status APPROVED. Repeating a status the bill already has sends nothing. Deleting a draft sends nothing, since you never heard about it. The same status can arrive twice when a bill returns to it, such as a failed payment retried through PAYMENT_INITIATED.
Editing a bill sends no event. A new memo, invoice number, due date, contact, line item or payment type changes what GET /bills/{bill_id} returns, and you see it on the bill’s next status move. Poll the bill, or ask us to add field-level events if you need them sooner.
status values: DRAFT_PROCESSING, DRAFT, PAYMENT_INFO_NEEDED, PENDING, APPROVED, REJECTED, SCHEDULED, PAYMENT_INITIATED, PAYMENT_DELIVERED, PAYMENT_FAILED, PAYMENT_CANCELED, CANCELED.
payment_type values: ACH, WIRE, CHECK, CRYPTO, INTERNATIONAL_PAYMENT_FX.
Line items and documents are not included. Read them from GET /bills/{bill_id}. bill_total is the sum of the line items at the time of the event, and null until the bill has line items, as on GET /bills/{bill_id}.
The event shortens very long vendor_name, invoice_number, description, and memo values to keep the payload small. GET /bills/{bill_id} returns them in full.
A submitted bill that is moved back to draft and then deleted sends
bill.updated with status CANCELED, like any other cancel of a bill you have seen.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. Each item carries kind (document or answers), the
proof_type for a document, and a human-readable detail, so route on kind
and proof_type rather than parsing the text. required_proof_types is the
document half of the same list, as proof_type values the upload endpoints
accept. completed_at is what says the request is done. It is null while
anything is left.
A document leaves outstanding when it is uploaded, and also when the business
explains that it cannot provide
it. Both settle
the document and both emit info_request.updated.
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.