How ACH payouts work through Bridge
Bridge (bridge.xyz) is the payout rail of Magic's dollar mode. Its liquidation addresses turn a USDC transfer into a bank payment with no manual step: USDC arrives at an address, Bridge converts it to dollars and pays a bank account by ACH. Creator fees are held in the MagicTreasury on BNB Chain until each payout cycle; this page covers everything from the moment a creator's share leaves the treasury to the moment it lands in their X Money balance, exactly as Bridge documents it. Every Bridge endpoint, field, state and timing below is taken from Bridge's API documentation at apidocs.bridge.xyz, and each part lists the pages it relies on.
Paths are relative to https://api.bridge.xyz/v0. Every request authenticates with an Api-Key
header, and every POST Magic makes carries an Idempotency-Key header.
Who is who
| Bridge object | In Magic | How many |
|---|---|---|
| Developer | Magic: holds the API key and receives the webhooks | One |
| Customer | Magic's operating company, onboarded as a business customer | One |
| External account | A creator's X Money account: account and routing number, the creator's name and address | One per creator (a new one if the creator changes details) |
| Liquidation address | The creator's personal payout address on Base, bound to that external account, paying out in USD by ACH | One per creator |
| Drain | One payout: a USDC deposit to the address, converted and paid by ACH | One per payout |
Magic (Bridge developer: API key, webhook endpoint)
└── Customer: Magic's operating company (type "business")
├── External account ── creator A's X Money (individual, checking)
│ └── Liquidation address ── 0x…A on Base: USDC in, USD out by ACH
│ └── Drains ── one per payout: deposit tx hash → ACH trace number
├── External account ── creator B's X Money
│ └── Liquidation address ── 0x…B on Base
└── …Bridge has two kinds of customer, individuals and businesses. Magic's company is onboarded once,
through Bridge's hosted onboarding (POST /kyc_links, with "type": "business") or the Customers
API (POST /customers). Creators are not Bridge customers and never see a Bridge screen: each
creator's X Money account is registered as an external account under Magic's customer — the
pattern Bridge's cross-border payments guide uses for a business that pays its suppliers, with "an
external account that stores a supplier's bank details".
A liquidation address is, in Bridge's words, "a permanent payment route which ties a blockchain address to either a fiat or blockchain address". Bridge refuses to create a second liquidation address for the same customer with the same source chain, source currency and destination. Every Magic address has a different destination — the creator's own external account — so the rule also works as a guard: one creator, one address.
Sources: Create your first customer · Customers overview · Cross-border payments · Liquidation address · Authentication · Idempotence
Registering the creator's X Money account
A creator signs in with X once on the Magic site and enters their X Money account and routing number once. Until then, their share accumulates in the MagicTreasury under their handle, and it never expires. Magic registers the details with Bridge:
POST /customers/{customerID}/external_accounts, where {customerID} is Magic's customer.
The account belongs to the creator, not to Magic's company, so every owner field names the creator: it is a third-party individual account held under Magic's customer. The documented request has no separate third-party switch; the owner fields carry it.
{
"currency": "usd",
"account_type": "us",
"bank_name": "Cross River Bank",
"account_name": "X Money",
"first_name": "<creator's first name>",
"last_name": "<creator's last name>",
"account_owner_type": "individual",
"account_owner_name": "<creator's full legal name>",
"account": {
"routing_number": "<X Money routing number>",
"account_number": "<X Money account number>",
"checking_or_savings": "checking"
},
"address": {
"street_line_1": "<street number and name>",
"city": "<city>",
"state": "<state>",
"postal_code": "<ZIP code>",
"country": "USA"
}
}| Field | Value for an X Money account |
|---|---|
currency | usd |
account_type | us — a US bank account |
bank_name | Cross River Bank, the bank that holds X Money accounts |
account_name | A label for the account |
account_owner_type | individual |
account_owner_name, first_name, last_name | The creator's legal name, as on their X Money account |
account.routing_number, account.account_number | From the account details in X Money |
account.checking_or_savings | checking |
address | The creator's address: street_line_1, city, state, postal_code, country |
Bridge's response returns the external account's id, only the last four digits of the account
number (account.last_4), beneficiary_address_valid, and a payment_rails object: supported
lists the USD rails the account can receive (for example ach, ach_same_day, fednow) and
unsupported_reasons says why any other rail is excluded. Magic stores the id and the last four
digits; the full numbers go to Bridge and are never shown back.
Bridge validates US beneficiary addresses: street line 1, city, postal code and country are required, and state as well for the United States; street line 1 must contain a street number and be 3 to 35 characters long; PO boxes and PMBs are refused. Magic's form applies the same rules before it submits, so a mistake is corrected on the spot instead of surfacing later at the bank.
When a creator changes their X Money details, Magic registers the new account, points the
existing liquidation address at it (PUT /customers/{customerID}/liquidation_addresses/{liquidationAddressID}
with the new external_account_id, a field Bridge lets you update on its own) and deactivates the old
account (POST /customers/{customerID}/external_accounts/{externalAccountID}/deactivate). The
creator's payout address never changes.
Sources: External accounts · External account validations · USD integration guide · Create an external account · Deactivate an external account · Update a liquidation address
Creating the creator's liquidation address
POST /customers/{customerID}/liquidation_addresses
{
"chain": "base",
"currency": "usdc",
"external_account_id": "<the creator's external account id>",
"destination_payment_rail": "ach",
"destination_currency": "usd",
"destination_ach_reference": "CREATORFEE",
"custom_developer_fee_percent": "0.0",
"return_instructions": { "address": "<Magic's settlement address on Base>" }
}| Field | What it does |
|---|---|
chain, currency | What the address accepts, and where: USDC on Base. base is Bridge's identifier for Base, as a payment_rail value and as a key of supported_currencies. |
external_account_id | The creator's X Money account, registered in the step above. |
destination_payment_rail | ach. The alternative is wire, with an optional destination_wire_message. |
destination_currency | usd. |
destination_ach_reference | A reference carried with each ACH payment. Bridge documents ACH references as at most 10 characters (letters, digits and spaces) that may appear on the recipient's statement; CREATORFEE fits. |
custom_developer_fee_percent | Bridge can withhold a developer fee from every drain. Magic sets none: its 10% stays in the MagicTreasury, and only the creator's share is ever sent. |
return_instructions | Where Bridge sends funds if a payment fails or is returned: an address and an optional memo. It replaces the deprecated return_address. |
The response carries the new address's id, its blockchain address — which becomes the creator's
personal payout address — its state (active) and supported_currencies, a map from each chain to
the currencies the address accepts.
Bridge warns that funds sent in a currency not listed in supported_currencies may be unrecoverable,
and that the list can change over time and should be re-read rather than cached. The settlement
service therefore re-reads the address (GET /customers/{customerID}/liquidation_addresses/{liquidationAddressID})
before every payout and sends only when it is active and lists usdc on base.
Bridge also offers a multichain option: "chain": "evm" generates one address usable across every
supported EVM chain (Bridge names Ethereum, Polygon, Base and Tempo), and "currency": "all_supported"
accepts every currency Bridge supports there. Bridge marks this option as beta, and for such
addresses it supports only its crypto return policy, not return_instructions.
Magic's design works with either form; it sends USDC on Base in both.
Sources:
Liquidation address ·
Offramp with a liquidation address ·
Multichain and multicurrency liquidation addresses ·
Tempo integration guide (a liquidation address with destination_ach_reference) ·
USD integration guide ·
Supported blockchains ·
Developer fees ·
Changelog ·
Get a liquidation address
The settlement leg before Bridge
Creator fees arrive in BNB, in the MagicTreasury on BNB Chain. Neither BNB nor BNB Chain appears anywhere in Bridge's documentation. Bridge's liquidation addresses take stablecoins on the chains it supports: its multichain guide names Ethereum, Polygon, Base and Tempo, and shows USDC accepted on Base. So before Bridge is involved, each payout cycle runs three public, on-chain steps:
- The creator's share leaves the treasury in a
Payoutwhoserefis the keccak256 hash of the creator's lowercase handle, so anyone can tie it to them. - BNB → USDC on BNB Chain, with a quoted minimum output.
- USDC from BNB Chain to Base.
It then sends each creator's share to that creator's liquidation address as one USDC transfer per creator per cycle, so that every drain on Bridge's side matches exactly one transaction on Magic's.
Four details of Bridge's rules shape that transfer:
- USDC, not USDT. Bridge's cutoff table notes that USDT, unlike its other supported stablecoins, "does not convert at a 1:1 peg with USD, and must be traded". Magic settles in USDC.
- Whole cents. Bridge processes only amounts expressible in whole US cents and discards any fractional cent. The settlement service sends amounts already cut to the cent and carries the remainder forward in the creator's balance.
- Minimums. Bridge enforces a minimum per route, after developer fees; deposits below it are neither credited nor returned, and a drain that falls below the route minimum is canceled. Magic's payout minimum sits above Bridge's minimum for the route, so no payout is ever dust.
- Charges. Bridge's pricing is agreed with Bridge directly. Its precision guide shows how to work back from the amount that should arrive to the amount to send; the settlement service does exactly that, so the dollars that land equal the creator's share, and the difference is paid from Magic's 10%.
Sources: Multichain and multicurrency liquidation addresses · Payment routes · Processing windows and cutoff times · Precision and rounding · Minimums · Drains · Pricing
What happens when the USDC arrives
Each deposit to a liquidation address creates a drain: Bridge converts the USDC and pays the bound bank account. Bridge's liquidation guide separates two kinds of rail: on real-time rails (such as wire) funds are sent at once; on batch rails (such as ACH) they are queued and processed daily.
Drain states. These are Bridge's exact state names; the right-hand column is what Magic's ledger does with each.
| State | Bridge's meaning | Magic's ledger |
|---|---|---|
in_review | A temporary, rarely triggered state that typically resolves within seconds; if it is unconfirmed after 24 hours, Bridge contacts the developer | Payout shown as processing |
funds_received | Bridge has received the funds and is processing them | Drain matched to the Base transfer |
payment_submitted | Bridge has submitted the payment | ACH in flight |
payment_processed | The payment is complete and the funds have reached the destination; for ACH, the drain's destination then includes the trace_number | Payout marked paid; trace number published |
undeliverable | Bridge could not send the funds, for example because of an invalid routing or account number | Amount returned to the creator's balance; creator asked to check their details |
returned | The payment was sent but failed, and the funds came back to Bridge | As above |
refund_in_flight | A refund has been initiated and is in progress | Awaiting the returned USDC |
refunded | Returned funds have been delivered to the configured return address | Returned USDC matched back at Magic's settlement address and held for the creator |
refund_failed | A refund attempt failed | Held and resolved with Bridge |
missing_return_policy | Bridge needs a crypto return policy to return the deposit | Prevented by configuration: every address has return_instructions, and the account has a static-address return policy |
error | A problem prevented processing; manual intervention may be required | Held; never re-sent blind |
canceled | Canceled and queued for return, for example below the route minimum | Held until refunded, then returned to the creator's balance |
A drain only moves forward: funds_received → payment_submitted → payment_processed.
Timing. Bridge uses fiat rails on banking days and during banking hours:
| Rail | Cutoff (ET) | Settlement | Bridge's notes |
|---|---|---|---|
| Next-day ACH | 4:45 PM | 8:30 AM the next business day | Batches go out each banking-day evening; ACH funds typically land in 1–2 banking days |
| Wire | 4:45 PM | Up to 2 hours after sending | After the cutoff, sent the next banking day; receiving banks process wires at their own speed |
| FedNow | None | Seconds | 24/7/365; the recipient bank must support FedNow |
Payments that miss a cutoff go out the next day, and ACH and wire payments initiated on a Federal Reserve holiday are queued for the next business day (for the rest of 2026: 12 October, 11 November, 26 November and 25 December). Each payout cycle therefore finishes its Base transfers well before 4:45 PM ET, so each payout can join that evening's ACH batch.
Webhooks. Magic registers one HTTPS endpoint (POST /webhooks). New endpoints start
disabled; Magic tests delivery with POST /webhooks/{webhookID}/send and then enables the
endpoint with PUT /webhooks/{webhookID}. It subscribes to the liquidation_address.drain category,
whose events are created, updated and updated.status_transitioned. The event_object of each
event is the drain exactly as the API returns it. Every delivery carries an X-Webhook-Signature
header of the form t=; Magic joins the timestamp and the raw request
body with a dot, takes the SHA-256 digest and verifies the signature with the endpoint's public key.
It refuses events older than ten minutes with a 400, as Bridge advises against replays (a retry
arrives with a fresh timestamp), and answers everything else with a 200 at once. An unreachable
endpoint is retried with exponential backoff for up to two days.
Backstops. Webhooks are not the only source. The reconciler also reads each address's drains
(GET /customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains), the drains of
every address at once (GET /liquidation_addresses/drains), and the account's webhook events
(GET /webhook_events, the last 90 days in event_sequence order) to replay any gap.
Idempotency. Bridge requires an Idempotency-Key on every POST and honours it for 24 hours:
a retry with the same key returns the original response and creates nothing new. A reused key with
a changed body is an error, and a key reused after 24 hours returns 422. Magic generates a UUID
for each intended operation — registering an account, creating an address — writes it to its
write-ahead ledger before calling Bridge, and reuses it on every retry. On the receiving side, each
webhook's event_id is globally unique, and Bridge notes it is useful as an idempotency key: the
ledger applies each event_id once and ignores repeats. Registrations are paced under Bridge's
global rate limit of 10 API calls per second.
Sources: Drains · Offramp with a liquidation address · Processing windows and cutoff times · Holidays · Returns · Webhooks overview · Webhook signature · Webhook event structure · Create a webhook endpoint · List webhook events · Drain history · Activity across all customers · Idempotence · Fiat payout configuration
Reconciliation: one payout, four records
Every dollar payout is tied together by identifiers that each side publishes:
| Record | Identifier | Source |
|---|---|---|
| Treasury | The BNB Chain transaction of the Payout, whose ref is the hash of the creator's handle | The MagicTreasury's Payout event |
| Base | The Base transaction hash of the USDC transfer | Magic's settlement service |
| Bridge | The drain's id, deposit_tx_hash, amount, state and destination.external_account_id | The drain webhook and drain history |
| Bank | destination.trace_number — a unique 15-digit number for each ACH payment (destination.imad for a wire) | The drain, once payment_processed |
A payout is marked paid only when the drain's deposit_tx_hash equals the Base transfer's hash,
the drain belongs to that creator's liquidation address, its external_account_id is the creator's
current X Money account, its amount agrees with the ledger entry, and its state is
payment_processed; the trace number Bridge then adds is recorded and published. Because each cycle
sends exactly one transfer per creator, every drain matches exactly one ledger entry. A drain that
does not match is held and investigated, never re-sent blind.
The proof page shows, for every payout, the X account, the coins and fee payments behind
it, the treasury Payout, the BNB-to-USDC swap, the Base transfer, the drain's state and the ACH
trace number.
Sources: Drains · Payment tracking identifiers · USD integration guide
Landing in X Money
X Money accounts have their own account and routing numbers at Cross River Bank. X's own Money FAQ says of those details: "Use these details for deposits and wire transfers from U.S. banks", and "You can set up your Money account to receive direct deposits." A Bridge ACH payout to those numbers is an ordinary incoming ACH credit to the creator's own account: no X Money send, request or claim is involved.
For USD ACH, Bridge originates payouts under the name of the relevant Bridge entity; its payout
configuration for usd.ach is bridge. Wires are originated by default under the developer's
name — here, Magic's company. The CREATORFEE reference travels with each ACH payment and may
appear on the creator's statement.
Bridge's cutoff table says next-day ACH funds typically land in 1–2 banking days, and the FAQ Bridge provides for developers' users puts next-day ACH at 1–3 days. A creator can expect a payout in their X Money balance within 1–3 business days of the cycle that sent it, and the proof page shows the trace number from the moment Bridge reports it.
Sources: Fiat payout configuration · Processing windows and cutoff times · Bridge FAQ · USD integration guide
FedNow, the faster rail
Bridge offers FedNow offramps: USD payouts that run 24/7/365 and settle in seconds, with liquidation
addresses among the products that can use them. Bridge currently opens FedNow offramps by invitation,
as a beta with a waitlist. Only an account whose payment_rails.supported includes fednow can
receive them, and Bridge asks for refund handling to be configured first, since a receiving bank can
still reject an individual payment.
Where Bridge enables FedNow for Magic's account and reports a creator's X Money routing number as
FedNow-eligible, Magic switches that creator's liquidation address from ach to fednow through the
same PUT used for account changes. Those payouts reach X Money in seconds, at any hour, and carry an
end_to_end_id where an ACH payment carries a trace number.
Sources: USD integration guide · Processing windows and cutoff times · Payment tracking identifiers · Changelog · Update a liquidation address
Magic is independent. It is not affiliated with, endorsed by or sponsored by Bridge, X Corp. or X Payments LLC. Bridge is Magic's payout rail for dollars, described here from its public API documentation. X Money is a destination for payouts, not a partner.