Skip to main content
Every event Meow sends has the same envelope. The 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 as cash_account_<uuid> or bridge_wallet_<uuid>.
  • Resource IDs (ach_transfer.id, wire_transfer.id, inbound transaction id, 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.
    Treat resource IDs as tokens; don’t parse them.
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

Same status 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 as ach_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 emits crypto_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 sends bill.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.
The agreements the business has to accept, tracked against the consent record that backs consent_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 via POST /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 and data.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 as application.*: 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.