> ## Documentation Index
> Fetch the complete documentation index at: https://agents.laso.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Bank accounts: give your agent real banking rails

> Open a US bank account for a managed Laso account, retrieve its routing and account numbers, and move money between dollars and USDC. Your agent can drive the whole setup except identity verification.

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.

<Info>
  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](/guides/managed-agent-wallet).
</Info>

## The two account types

<CardGroup cols={2}>
  <Card title="On-ramp: dollars in" icon="building-columns">
    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.
  </Card>

  <Card title="Off-ramp: dollars out" icon="arrow-right-arrow-left">
    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.
  </Card>
</CardGroup>

## Step 1: open the banking profile

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/createBankingProfile \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"userId":"usr_..."}}'
```

If the owner has not verified their identity yet, this returns a link rather than a profile:

```json theme={null}
{ "result": { "kycRequired": true, "kycUrl": "https://..." } }
```

<Warning>
  **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.
</Warning>

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:

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/getBankingApplication \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"userId":"usr_..."}}'
```

```json theme={null}
{
  "result": {
    "applicationId": "...",
    "applicationStatus": "in_progress",
    "ready": false,
    "missingFields": ["ssn"],
    "hostedOnly": false
  }
}
```

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:

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/updateBankingApplicationDetails \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{
        "userId":"usr_...",
        "firstName":"Jane","lastName":"Doe",
        "dateOfBirth":"1990-04-17",
        "nationalities":["US"],
        "emailAddress":"jane@example.com",
        "address":{"street1":"1 Main St","city":"Austin","region":"TX","postal_code":"78701","country":"US"},
        "employmentStatus":"employed",
        "purposeOfAccount":["sending_and_receiving_payments"],
        "sourceOfWealth":["employment"],
        "ssn":"123456789"
      }}'
```

| Field              | Rule                                                                                                                                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `dateOfBirth`      | ISO `YYYY-MM-DD`. The person must be 18 or older.                                                                                                                                                                                                                  |
| `nationalities`    | Non-empty array of ISO 3166-1 alpha-2 codes, e.g. `["US"]`.                                                                                                                                                                                                        |
| `employmentStatus` | `employed`, `self_employed`, `unemployed`, `student`, `retired`.                                                                                                                                                                                                   |
| `purposeOfAccount` | Non-empty array: `investing`, `sending_and_receiving_payments`, `storage_of_funds_or_digital_assets`, `making_online_payments`, `trading_on_other_platforms`.                                                                                                      |
| `sourceOfWealth`   | Non-empty array: `investments`, `employment`, `court_settlement`, `lottery_winnings`, `retirement_income`, `savings`, `sale_of_assets`, `family_funds`, `gambling_winnings`, `gift`, `inheritance`, `insurance_claim`, `loan`, `redundancy_severance`, `benefits`. |
| `ssn`              | Required for US persons. Nine digits, no hyphens. Reported in `missingFields` when needed.                                                                                                                                                                         |

<Warning>
  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.
</Warning>

Then submit for approval:

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/submitBankingApplication \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"userId":"usr_..."}}'
```

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:

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/createBankingAccount \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"userId":"usr_...","accountType":"onramp"}}'
```

For an off-ramp, first register who gets paid, then point the account at them:

```bash theme={null}
# 1. The person or company being paid. `address` is required for a bank account.
curl .../createBankingRecipient -d '{"data":{"userId":"usr_...","name":"Jane Doe","address":{"street1":"1 Main St","street2":"Apt 2","city":"Austin","region":"TX","postal_code":"78701","country":"US"}}}'

# 2. Their bank account, returns destinationId
curl .../addBankingDestination -d '{"data":{"userId":"usr_...","recipientId":"...","destination":{"destination_type":"fiat_us","name":"Jane checking","aba_routing_number":"021000021","account_number":"123456789","account_type":"checking","account_holder_name":"Jane Doe","bank_name":"Chase"}}}'

# 3. The off-ramp account
curl .../createBankingAccount -d '{"data":{"userId":"usr_...","accountType":"offramp","fiatDestinationId":"..."}}'
```

<Warning>
  **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.
</Warning>

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.

## Step 4: retrieve your bank details

To read the details back at any time, without creating anything:

```bash theme={null}
curl https://us-central1-kyc-ts.cloudfunctions.net/listBankingAccounts \
  -H "Authorization: Bearer YOUR_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"userId":"usr_..."}}'
```

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**: `depositCryptoAddress` to send USDC to, and the `fiatDestinationId` it pays out to.

<Warning>
  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.
</Warning>

## Following the money

Every ramp transaction is mirrored as it settles, so you can follow one without polling the partner:

```bash theme={null}
curl .../listBankingTransactions -d '{"data":{"userId":"usr_..."}}'
curl .../getBankingTransaction  -d '{"data":{"userId":"usr_...","transactionId":"..."}}'
```

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 when one reaches a terminal state.

<Note>
  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.
</Note>

## What your agent can and cannot do

| Step                                | Agent                      | Human                                     |
| ----------------------------------- | -------------------------- | ----------------------------------------- |
| Open the banking profile            | Yes                        |                                           |
| Identity verification               |                            | **Required.** Agent passes `kycUrl` along |
| Read application requirements       | Yes                        |                                           |
| Submit application details          | Yes                        |                                           |
| Accept legal attestations           | Yes, on the owner's behalf | Must have agreed to the terms             |
| Open on-ramp / off-ramp account     | Yes                        |                                           |
| Retrieve bank details               | Yes                        |                                           |
| Register recipients, send transfers | Yes                        |                                           |
