Skip to main content
A managed Laso account can have real banking rails attached to it: a US bank account that receives dollars and turns them into USDC in the managed wallet, and a crypto address that pays dollars out to a bank account. Your agent can open both, and retrieve the resulting bank details, through ordinary authenticated calls. One step is deliberately not automatable. Identity verification has to be completed by the person who owns the account. Everything around it, including the rest of the bank application, is something your agent can do on its own.
These calls are Firebase callables at https://us-central1-kyc-ts.cloudfunctions.net/<name>, authorized with the id_token from sign-in. Arguments are wrapped in a data object and replies in a result object, the same convention as the managed wallet.

The two account types

On-ramp: dollars in

A virtual US bank account with real ACH and wire details. Dollars sent to it are converted and delivered as USDC to the managed wallet. Use it to get paid, or to fund the agent from a normal bank transfer.

Off-ramp: dollars out

A Solana deposit address. USDC sent to it is paid out automatically to a bank account you registered beforehand. Use it to pay someone in dollars.

Step 1: open the banking profile

If the owner has not verified their identity yet, this returns a link rather than a profile:
This is the one step your agent cannot do. Give kycUrl to your human, wait for them to finish, then call again. Never attempt to complete an identity check on someone else’s behalf.
Once they have verified, the same call returns profileId, applicationStatus, and an applicationUrl. Identity carries over automatically, so what remains is a short set of non-identity questions.

Step 2: complete the application

Your agent can answer the remaining questions itself. Start by reading what is outstanding:
If hostedOnly is true, this particular application can only be finished on the partner’s own page. Give the human applicationUrl and skip ahead to step 3. Otherwise submit the details:
These are the account owner’s real personal details on a real bank application. Send only values the owner actually gave you. Do not invent, guess, or infer them: a wrong answer is a compliance problem for your human, not a retryable error.
Then submit for approval:
The required legal attestations (e-sign, terms of service, privacy policy, funds transfer agreement) are accepted on the owner’s behalf as part of this call, so only make it once they have agreed to those terms. Retrying is safe: attestations already recorded are not sent again. Poll getBankingProfileStatus with the same body until applicationStatus shows approval.

Step 3: open the account

For an on-ramp:
For an off-ramp, first register who gets paid, then point the account at them:
A recipient needs an address before a bank account can be attached to it. That is the postal address of whoever is being paid, not the bank’s address: street1, optional street2, city, region, postal_code, country. A crypto destination does not need one; fiat_us and fiat_iban do, and step 2 fails with failed-precondition without it.Already created a recipient without an address? Pass recipientAddress to addBankingDestination and it sets the address before attaching the account, so you do not have to create a second recipient.
Use only the address and bank details your human actually gave you. Do not guess an address to get past the requirement. createBankingAccount is idempotent. Calling it again returns the account that already exists rather than opening a second one.

Renaming and deleting recipients

A destination’s nickname is the only editable field. Set or change it at any time:
An empty string clears the nickname; 40 characters max. GET /bank-recipients and the dashboard both show it. If any bank detail is wrong, delete the recipient and create a new one:
Deleting a recipient is irreversible and cascades: its destinations are removed, and any off-ramp account paying out to them is closed, including its USDC deposit address. Confirm with your human before deleting. Your human can also manage recipients on their dashboard; both surfaces use these same calls, so changes are visible to both of you.
To actually pay someone, you only need steps 1 and 2 of the off-ramp. Once a destination exists, GET /send-bank-payment sends dollars to it over x402 in a single call and opens the off-ramp account for you. Create the off-ramp account yourself only when you want the deposit address to hand to something else.

Step 4: retrieve your bank details

To read the details back at any time, without creating anything:
Each entry carries accountId, accountType, and status, plus whichever side applies:
  • On-ramp: bankAccount with account_holder_name, account_number, aba_routing_number, bank_name, bank_address, and capabilities such as ["ach","fedwire"]. These are the details to give whoever is paying.
  • Off-ramp: the fiatDestinationId it pays out to, and nickname when your human has named that destination. The off-ramp’s internal funding address is deliberately not returned. To pay a destination, call GET /send-bank-payment, which opens the off-ramp and handles the funding leg for you.
When an entry has a nickname, lead with it. Your human picked that label, so it is how they think of the account: say “Rent account” rather than “off-ramp acct_9f2c...”, and name it in any confirmation before you move money. Keep the bank name, last four digits, or accountId as the secondary detail that tells two similar accounts apart, and fall back to accountType and the bank details only when there is no nickname.
These are real bank details. Share them only with people who are meant to pay the account, and treat the account number like a credential.

Following the money

Every ramp transaction is mirrored as it settles, so you can follow one without polling the partner:
A transaction reports status (pending, then completed, failed, or cancelled), direction (onramp or offramp), amount with amountAsset, sendAmount with sendAsset, and txHash once it settles on-chain. Your human is notified automatically at each meaningful step: profile creation, application submission, document review, account provisioning, transfers, payouts, and terminal transaction states. To receive those same events yourself instead of polling, register a webhook with POST /register-webhook: every notification is then also POSTed to your URL with a Standard Webhooks signature. See receiving notifications by webhook.
A fiat on-ramp settles in two stages. The bank transfer clears first, and the USDC arrives in the managed wallet minutes to hours later. Both stages show up on your human’s dashboard, so a gap between “bank transfer complete” and the wallet balance moving is expected rather than an error.

What your agent can and cannot do