Skip to main content
This guide explains how to move funds with the Meow API. It covers:
  • Internal book transfers between bank accounts
  • USDC transfers to cryptocurrency addresses
  • International payments in a recipient’s local currency

Prerequisites

  • A Meow account with enabled bank accounts
  • API key permissions:
    • Book transfers: accounts:read and transfers:book:write
    • USDC transfers: accounts:read, accounts:payment-networks, and transfers:usdc:write
    • International payments: contacts:read, contacts:write, and transfers:international:write
  • A cryptocurrency contact for USDC transfers (see Contact Management Guide)

Authentication Overview

The headers you send depend on the type of API key:
  • Entity API keys scope all requests to a single entity. No x-entity-id header is required and you can only move funds between accounts that belong to that entity.
  • Global API keys can access multiple entities, but every request must include an x-entity-id header that identifies the source entity for the request. Use GET /v1/api-keys/accessible-entities to discover which entities you can access. When booking transfers, the destination account can belong to any other entity you have access to, as long as the accounts remain compatible.
Regardless of the key type, book transfers can only be created between accounts that share the same bankProductType.

Book Transfers

Book transfers move funds internally between two accounts you control. The source account is chosen by the path parameter, and the destination is provided in the request body.

Workflow with Entity API Keys

1. List accounts to find eligible source and destination accounts:
Record each account’s accountId and bankProductType. You must choose a destination account with the same bankProductType as the source. 2. Create the book transfer:
Replace {source_account_id} and to_account_id with the account IDs you gathered. The Idempotency-Key must be unique per transfer attempt. Example response:

Workflow with Global API Keys

1. Discover accessible entities:
Use the returned IDs to decide which entity you are operating on. 2. List accounts for a specific entity:
Locate source accounts within the selected entity that share the same bankProductType as potential destination accounts. Repeat this call for each entity you have access to so you can identify compatible cross-entity pairs. 3. Create the book transfer using the source entity header:
The x-entity-id value must match the source account’s entity. As long as you have access, the destination account can belong to a different entity that shares the same bankProductType.

Book Transfer Tips

  • Pick a fresh Idempotency-Key header for each attempt so retries do not create duplicate transfers. The legacy idempotency_key body field still works but is deprecated; when both are sent they must match.
  • Verify both accounts are active, denominated in the same currency, and share a bankProductType even when they belong to different entities.
  • Transfers fail if the destination account’s bankProductType differs from the source.
  • API-based transfers are blocked when Security Policy Spend controls are enabled for the entity; adjust the policy or rely on the dashboard instead.

USDC Transfers

USDC transfers send funds from a checking account to a cryptocurrency contact.

Step 1: List Accounts

Example response:

Step 2: Verify USDC Support

Look for payment networks with "type": "USDC" and "transferOut": true to confirm the account can originate USDC transfers on the listed blockchains.

Step 3: Create the USDC Transaction

Example response:

Transaction Status

Possible statuses after submission:

International Payments

International payments pay a contact in their own currency, converting from US dollars at the rate quoted when you send. To send US dollars instead, including to a bank outside the US, use a wire.

Step 1: Find out what the destination needs

Bank details differ by destination. Some countries route on an IBAN, others on a domestic routing code, and some also want the recipient’s address. Ask before you build the contact:
Check supported first, since not every currency reaches every country. When it is false, unsupported_reason says why. When it is true, required_fields lists exactly the fields to collect, each with an optional pattern to validate against.

Step 2: Create the contact

Send the fields the previous step listed as international on the contact. Provide exactly one of international, counterparty, or crypto_address:

Step 3: Quote the payment

Quoting prices the payment without sending it, so you can show the rate, the fee, and the total debit before committing. Fix either leg: pass recipient_amount to send an exact amount in their currency, or source_amount to spend an exact number of US dollars.
The response returns rate, fee, total_debit, and fixed_side naming the leg you fixed.
A quote reserves nothing. The payment is priced again when you send it, so the figures can move if the rate does.

Step 4: Send the payment

purpose is required and describes why you are paying. Some destinations also want a purpose_code, and invoice_number, invoice_date and reference are available where the recipient’s bank expects them. The response returns approval_id and a status of either processing, meaning it is on its way, or pending_approval, meaning the entity’s security policy requires someone to approve it before it moves.
The Idempotency-Key header is required on international payments, so a retried request cannot send a second payment.

Checking Transfer Status

After initiating a transfer, use the corresponding GET endpoint with the transfer ID returned from the create call to check its current status.

ACH Transfers

Use the id from the create ACH response (e.g. ach_...) or the transaction group ID (e.g. withdrawal_ach_...) from a transaction listing:

Wire Transfers

Use the transaction group ID for the wire transfer:

USDC Transactions

Use the id from the create USDC response:
These GET endpoints return details for both incoming and outgoing transfers. For example, you can retrieve details of an incoming ACH deposit using the same endpoint used to check the status of an outgoing ACH transfer you initiated.

Best Practices

  • Verify recipients: Confirm cryptocurrency addresses and contact static memos before initiating transfers.
  • Use meaningful references: Populate description (book transfers) or internal_note (USDC transfers) with reconciliation-friendly values.
  • Start small: Send a nominal amount when onboarding a new recipient.
  • Protect secrets: Keep API keys and transaction data out of unsecured channels.
  • Monitor statuses: Follow up with support if a transfer remains in error.