# Account & Funds Management via API *If you haven't already, [Sign Up for Sandbox Access](https://rail.io/contact-us) to get your client ID and secret to work through this Build Guide!* ## What is Account & Funds Management? Account & Funds Management encompasses the complete lifecycle of opening accounts for your customers, obtaining deposit instructions, monitoring account status changes, and tracking incoming funds. This guide will walk you through best practices for managing accounts and funds programmatically via the Rail API. Rail supports multiple account types and currencies, allowing you to: - **Open deposit accounts** in various fiat and crypto currencies - **Monitor account status** changes through webhooks - **Generate deposit instructions** for customers to send funds - **Track incoming deposits** and transactions in real-time ## Core API Flow Sequence The standard API account management flow follows these key steps: 1. **POST** [`/v1/accounts/deposits`](/api-docs/openapi/rail-spec#operation/openAccount) - Open a new account 2. **GET** [`/v1/accounts/deposits/{id}`](/api-docs/openapi/rail-spec#operation/getAccount) - Check account status 3. **POST** [`/v1/subscriptions`](/api-docs/openapi/rail-spec#operation/createSubscription) - Subscribe to account webhooks 4. **POST** [`/v1/deposits`](/api-docs/openapi/rail-spec#operation/createDeposits) - Get deposit instructions 5. **GET** [`/v1/accounts/deposits/{id}/transactions`](/api-docs/openapi/rail-spec#operation/getTransactions) - Track incoming deposits ## Build Guide This guide should take no longer than 15 minutes and will allow you to open an account, set up monitoring, and track incoming funds in Sandbox. By the end of this guide you will have: 1. [Authenticated your request](#authenticating-your-request) 2. [Opened a new account for a customer](#step-1-open-a-new-account) 3. [Verified the account is ready](#step-2-check-account-status) 4. [Set up webhook subscriptions for monitoring](#step-3-create-webhook-subscriptions) 5. [Retrieved deposit instructions](#step-4-get-deposit-instructions) 6. [Tracked incoming deposits](#step-5-track-incoming-deposits) Let's go! ## Authenticating your request Every request you make to a Rail API endpoint requires an `AUTH_TOKEN`. We secure our endpoints using standards based OAuth2 Client Credentials Grant and scopes. To obtain the `AUTH_TOKEN`, you will need to authorize your account using your `BASE_64_ENCODED_CLIENTID_AND_SECRET` with the scopes you require: ```bash curl --location --request POST 'https://auth.layer2financial.com/oauth2/ausbdqlx69rH6OjWd696/v1/token?grant_type=client_credentials&scope=accounts:read+accounts:write+deposits:read+deposits:write+subscriptions:read+subscriptions:write' \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Cache-Control: no-cache' \ --header 'Authorization: Basic {BASE_64_ENCODED_CLIENTID_AND_SECRET}' ``` This gives you a response object containing your `AUTH_TOKEN`: ```javascript { "token_type": "Bearer", "expires_in": 43200, "access_token": {AUTH_TOKEN}, "scope": "accounts:read accounts:write deposits:read deposits:write subscriptions:read subscriptions:write" } ``` The scopes we'll need for this tutorial are: - `accounts:read` and `accounts:write` to open and query accounts - `deposits:read` and `deposits:write` to get deposit instructions and track deposits - `subscriptions:read` and `subscriptions:write` to set up webhooks for monitoring The full list of scopes are available [here](/guides/authentication). ## Step 1: Open a New Account Open a new account for a customer by calling the [`/v1/accounts/deposits`](/api-docs/openapi/rail-spec#operation/openAccount) endpoint. You'll need: - The `customer_id` from your onboarded customer (see [Customer Onboarding](/guides/customer_onboarding)) - An `account_id` that will be the unique identifier for this account (e.g., `CUSTOMERNAME_USD_001`) - The `product_id`: The type of account to open. Use `DEPOSIT_BASIC` for standard deposit accounts - The `asset_type_id`: The currency/asset type for the account (e.g., `FIAT_TESTNET_USD` for USD in sandbox) ```bash curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/accounts/deposits' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "customer_id": "INDIVIDUAL_CUSTOMER_001", "account_to_open": { "account_id": "CUSTOMER_USD_001", "product_id": "DEPOSIT_BASIC", "asset_type_id": "FIAT_TESTNET_USD" } }' ``` The response contains the `account_id` you provided: ```javascript { "data": { "id": "CUSTOMER_USD_001" } } ``` Important Name your accounts appropriately for your business needs (e.g., `CustomerName_USD_001`, `CustomerName_EUR_002`) to make them easy to identify and manage. ## Step 2: Check Account Status Before you can request deposit instructions, the account must reach `OPEN` status. Check the account status by calling the [`/v1/accounts/deposits/{id}`](/api-docs/openapi/rail-spec#operation/getAccount) endpoint: ```bash curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits/CUSTOMER_USD_001' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' ``` The response shows the account status and balance information: ```javascript { "data": { "id": "CUSTOMER_USD_001", "status": "OPEN", "asset_type_id": "FIAT_TESTNET_USD", "product_type": "DEPOSIT", "product_id": "DEPOSIT_BASIC", "customer_id": "INDIVIDUAL_CUSTOMER_001", "current_balance": 0, "available_balance": 0 } } ``` ### Account Status Meanings Accounts progress through different statuses during their lifecycle: - **PENDING** - Account is being set up and not yet ready for transactions - **OPEN** - Account is fully ready and can receive deposit instructions - **FROZEN** - Account has been temporarily locked for all actions (deposits, transfers, exchanges, withdrawals) - **EDD** - Account requires enhanced due diligence. The account will operate as if frozen - **CLOSED** - Account is permanently closed, no further actions can be performed - **DORMANT** - No activity seen in the last 12 months. Account is still available for use Critical Rule Deposit instructions will only be available when the account status is `OPEN` - not when it's in `PENDING` or any other status. Always verify the account status before attempting to get deposit instructions. ### When to Show Account as "Ready" to End Users **Scenario:** You want to display an account card or enable account features in your UI only when the account is truly ready to receive funds. **The Most Reliable Approach:** Don't rely solely on the account status being `OPEN`. Instead, actually request deposit instructions and confirm they are available. Here's why: There may be scenarios where an account shows `OPEN` status, but the underlying banking provider has not yet completed their approval process. In these edge cases: - The account status will be `OPEN` in Rail's system - However, deposit instructions may not yet be available - Attempting to get deposit instructions will return an error or empty response **Recommended Implementation:** ```bash # Step 1: Check account status GET /v1/accounts/deposits/{account_id} # Step 2: If status is OPEN, attempt to get deposit instructions POST /v1/deposits # Step 3: Only show account as "ready" if deposit instructions are successfully returned ``` This two-step verification ensures that: 1. The account is marked as `OPEN` by Rail 2. The underlying provider has approved and deposit instructions are actually available 3. Your customer can immediately use the account without errors **Example Flow:** ```javascript // Pseudo-code for checking account readiness async function isAccountReady(accountId) { // Check account status const account = await getAccount(accountId); if (account.status !== 'OPEN') { return false; } // Verify deposit instructions are available try { const deposit = await getDepositInstructions(accountId); return deposit.deposit_instructions && deposit.deposit_instructions.length > 0; } catch (error) { // Instructions not yet available return false; } } // Only show account card when truly ready if (await isAccountReady(accountId)) { displayAccountCard(); } ``` This approach provides the best user experience and prevents showing accounts as "ready" when they cannot actually receive funds yet. ### Retrieving Multiple Accounts You can also retrieve all accounts for a customer using the [`/v1/accounts/deposits`](/api-docs/openapi/rail-spec#operation/getAccounts) endpoint with query parameters: ```bash curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits?customer_id=INDIVIDUAL_CUSTOMER_001&status=OPEN' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' ``` This returns a paginated list of accounts: ```javascript { "data": { "accounts": [ { "id": "CUSTOMER_USD_001", "status": "OPEN", "asset_type_id": "FIAT_TESTNET_USD", "product_type": "DEPOSIT", "product_id": "DEPOSIT_BASIC", "customer_id": "INDIVIDUAL_CUSTOMER_001", "current_balance": 0, "available_balance": 0 } ] }, "links": { "self": "/v1/accounts/deposits?customer_id=INDIVIDUAL_CUSTOMER_001&status=OPEN&page=0&page_size=20", "first": "/v1/accounts/deposits?customer_id=INDIVIDUAL_CUSTOMER_001&status=OPEN&page=0&page_size=20", "prev": null, "next": null, "last": "/v1/accounts/deposits?customer_id=INDIVIDUAL_CUSTOMER_001&status=OPEN&page=0&page_size=20" } } ``` ## Step 3: Create Webhook Subscriptions Instead of constantly polling for account status changes, set up webhook subscriptions to receive real-time notifications. This is the recommended approach for production systems. ### Subscribe to Account Status Updates Create a subscription for account status changes using the [`/v1/subscriptions`](/api-docs/openapi/rail-spec#operation/createSubscription) endpoint: ```bash curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/subscriptions' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "event_type": "ACCOUNT_OPEN", "callback_url": "https://your-domain.com/webhooks/account-open" }' ``` The response includes a signature verification key for validating webhook payloads: ```javascript { "data": { "id": "sub_123456789", "event_type": "ACCOUNT_OPEN", "callback_url": "https://your-domain.com/webhooks/account-open", "signature_verification_key": "whsec_abc123..." } } ``` ### Subscribe to Deposit Instructions Updates Subscribe to the `ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE` webhook to know when deposit instructions become available or are updated: ```bash curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/subscriptions' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "event_type": "ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE", "callback_url": "https://your-domain.com/webhooks/deposit-instructions" }' ``` Why This Matters Deposit instructions on an account may be updated over time. Account numbers and banking details can change, so listening to this webhook ensures you always have current information. ### Subscribe to Transaction Events Set up subscriptions for tracking incoming deposits: ```bash # Subscribe to pending transactions curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/subscriptions' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "event_type": "TRANSACTION_PENDING", "callback_url": "https://your-domain.com/webhooks/transaction-pending" }' # Subscribe to posted transactions curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/subscriptions' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "event_type": "TRANSACTION_POSTED", "callback_url": "https://your-domain.com/webhooks/transaction-posted" }' ``` ### Recommended Webhook Events for Account Management | Event Type | When Triggered | Use Case | | --- | --- | --- | | `ACCOUNT_OPEN` | Account status changes to OPEN | Know when account is ready for deposit instructions | | `ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE` | Deposit instructions become available or are updated | Get notified of deposit instruction changes | | `ACCOUNT_FROZEN` | Account is frozen | Alert customer of account restrictions | | `ACCOUNT_EDD` | Account requires enhanced due diligence | Take appropriate compliance actions | | `TRANSACTION_PENDING` | Deposit detected but not yet posted | Notify customer of incoming funds | | `TRANSACTION_POSTED` | Deposit approved and posted to account | Update customer balance and confirm receipt | For more details on webhooks, see the [Subscriptions Guide](/guides/subscriptions). ## Step 4: Get Deposit Instructions Once the account status is `OPEN`, request deposit instructions using the [`/v1/deposits`](/api-docs/openapi/rail-spec#operation/createDeposits) endpoint. ### Supported Payment Rails by Currency Different currencies support different payment rails. For USD accounts, you can receive instructions for: - **ACH** - Automated Clearing House (domestic US transfers) - **FEDWIRE** - Federal Reserve Wire Network (domestic US transfers) - **SWIFT** - Society for Worldwide Interbank Financial Telecommunication (international transfers) For the complete list of supported payment rails for each currency, see the [Assets Guide](/guides/assets). ### Request Deposit Instructions Create a `PUSH` deposit to get the instructions customers need to send funds: ```bash curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/deposits' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "deposit_type": "PUSH", "deposit_destination": { "destination_account_id": "CUSTOMER_USD_001" }, "customer_name": "Jane Doe" }' ``` ### Understanding the Response For `FIAT_TESTNET_USD` accounts, you'll receive ACH, FEDWIRE, and SWIFT instruction types (production accounts for `FIAT_MAINNET_USD` support all three rails): ```javascript { "data": { "id": "deposit_987654321", "status": "REQUESTED", "created_timestamp": "2023-11-20T14:32:18.123456Z", "deposit_type": "PUSH", "deposit_destination": { "destination_account_id": "CUSTOMER_USD_001", "asset_type_id": "FIAT_TESTNET_USD" }, "customer_name": "Jane Doe", "deposit_source": { "deposit_instructions": [ { "instruction_type": "ACH", "account_holder_name": "Jane Doe", "account_number": "9695859732", "account_routing_number": "715960587", "description": "Deposit to CUSTOMER_USD_001", "asset_type_id": "FIAT_TESTNET_USD" }, { "instruction_type": "FEDWIRE", "account_holder_name": "Jane Doe", "account_number": "9695859732", "account_routing_number": "715960587", "account_holder_address": { "address_line1": "123 Main Street", "city": "Boston", "state": "MA", "postal_code": "02101", "country_code": "US" }, "institution_name": "Rail Banking Services", "institution_address": { "address_line1": "1 Financial Place", "city": "Boston", "state": "MA", "postal_code": "02101", "country_code": "US" }, "memo": "ea947e78-50ba-40b0-8e6e-32345eeb2cab", "asset_type_id": "FIAT_TESTNET_USD" }, { "instruction_type": "SWIFT", "account_holder_name": "Jane Doe", "account_number": "9695859732", "swift_code": "RAILUSXX", "account_holder_address": { "address_line1": "123 Main Street", "city": "Boston", "state": "MA", "postal_code": "02101", "country_code": "US" }, "institution_name": "Rail Banking Services", "institution_address": { "address_line1": "1 Financial Place", "city": "Boston", "state": "MA", "postal_code": "02101", "country_code": "US" }, "reference": "CUSTOMER_USD_001", "asset_type_id": "FIAT_TESTNET_USD" } ] } } } ``` ### Deposit Instructions for Crypto Accounts For crypto accounts, you'll receive blockchain addresses: ```bash curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/deposits' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' \ --data-raw '{ "deposit_type": "PUSH", "deposit_destination": { "destination_account_id": "CUSTOMER_USDC_001" }, "customer_name": "Jane Doe" }' ``` Response for crypto account: ```javascript { "data": { "id": "deposit_crypto_123", "status": "REQUESTED", "created_timestamp": "2023-11-20T14:35:22.456789Z", "deposit_type": "PUSH", "deposit_destination": { "destination_account_id": "CUSTOMER_USDC_001", "asset_type_id": "ETHEREUM_GOERLI_USDC" }, "customer_name": "Jane Doe", "deposit_source": { "deposit_instructions": [ { "instruction_type": "CRYPTO", "address": "0x9ED9961A87ba49511Cf522059df52e2a94eF188b", "blockchain": "ethereum", "network": "goerli", "asset_type_id": "ETHEREUM_GOERLI_USDC" } ] } } } ``` Important The `/v1/deposits` endpoint is the primary and most reliable method for getting deposit instructions. When the account status is `OPEN`, this endpoint will consistently return the appropriate instruction types for the account's asset type. For USD accounts, this includes ACH, FEDWIRE, and SWIFT instructions. See the [Assets Guide](/guides/assets) for supported payment rails by currency. ## Step 5: Track Incoming Deposits Once deposit instructions are shared with customers and they send funds, you need to track when those funds arrive. ### Understanding Deposits vs Transactions - **Deposit** - The request for deposit instructions (the `id` returned from `/v1/deposits`) - **Transaction** - The actual movement of funds into the account (linked via `category_id`) When a customer sends funds using the deposit instructions, Rail creates a transaction linked to the deposit. Important Note A transaction appearing in the Rail system means the deposit has reached our platform. Rail does not have the ability to track the status of deposits before they hit our platform (e.g., we cannot see that a wire transfer has been initiated but not yet received). Transaction notifications only occur once funds have actually arrived at Rail's banking partners. ### Webhook Sequence for Incoming Deposits When a deposit is received, you'll receive webhooks in this sequence: 1. **`TRANSACTION_PENDING`** - Sent when Rail detects the incoming deposit 2. **`TRANSACTION_POSTED`** - Sent once monitoring is completed and the transaction is approved Both webhooks include the transaction details with the `category_id` matching your deposit `id`. Example `TRANSACTION_PENDING` webhook payload: ```javascript { "event_type": "TRANSACTION_PENDING", "data": { "transaction_id": "txn_abc123", "account_id": "CUSTOMER_USD_001", "amount": 1000.00, "asset_type_id": "FIAT_TESTNET_USD", "category": "DEPOSIT", "category_id": "deposit_987654321", "status": "PENDING", "created_timestamp": "2023-11-20T15:00:00.000000Z" } } ``` ### API Polling Method Alternatively, you can poll for transactions using the account's transaction endpoint: ```bash curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits/CUSTOMER_USD_001/transactions' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' ``` Response with transaction details: ```javascript { "data": { "transactions": [ { "id": "txn_abc123", "account_id": "CUSTOMER_USD_001", "status": "POSTED", "amount": 1000.00, "asset_type_id": "FIAT_TESTNET_USD", "category": "DEPOSIT", "category_id": "deposit_987654321", "created_timestamp": "2023-11-20T15:00:00.000000Z", "posted_timestamp": "2023-11-20T15:05:00.000000Z" } ] }, "links": { "self": "/v1/accounts/deposits/CUSTOMER_USD_001/transactions?page=0&page_size=20", "first": "/v1/accounts/deposits/CUSTOMER_USD_001/transactions?page=0&page_size=20", "prev": null, "next": null, "last": "/v1/accounts/deposits/CUSTOMER_USD_001/transactions?page=0&page_size=20" } } ``` ### Filter Transactions by Deposit To find transactions for a specific deposit, filter by `category` and `category_id`: ```bash curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits/CUSTOMER_USD_001/transactions?category=DEPOSIT&category_id=deposit_987654321' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' ``` ### Check Updated Account Balance After a transaction is posted, verify the account balance was updated: ```bash curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits/CUSTOMER_USD_001' \ --header 'Authorization: Bearer {AUTH_TOKEN}' \ --header 'Content-Type: application/json' ``` The response shows the updated balances: ```javascript { "data": { "id": "CUSTOMER_USD_001", "status": "OPEN", "asset_type_id": "FIAT_TESTNET_USD", "product_type": "DEPOSIT", "product_id": "DEPOSIT_BASIC", "customer_id": "INDIVIDUAL_CUSTOMER_001", "current_balance": 1000.00, "available_balance": 1000.00 } } ``` ## API Account Management Best Practices ### 1. Always Verify Account Status Before Requesting Deposit Instructions Deposit instructions will only be available when the account status is `OPEN`. Attempting to get instructions for accounts in `PENDING` or other statuses will fail. **Recommended Flow:** ```bash # 1. Check account status GET /v1/accounts/deposits/{account_id} # 2. Only proceed if status is "OPEN" if status == "OPEN": POST /v1/deposits ``` ### 2. Use Webhooks Instead of Polling (When Possible) Set up webhook subscriptions for real-time notifications rather than continuously polling endpoints: - **`ACCOUNT_OPEN`** - Know immediately when account is ready - **`ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE`** - Get notified of instruction changes - **`TRANSACTION_PENDING`** and **`TRANSACTION_POSTED`** - Track incoming funds in real-time Benefits: - Reduces API load and costs - Faster response times - More reliable than polling intervals - Scales better for high-volume operations Note If webhooks don't work for your setup (e.g., firewall restrictions, infrastructure limitations, or compliance requirements), polling can be a reliable replacement. Implement polling with appropriate intervals (e.g., every 30-60 seconds for account status, every 2-5 minutes for transactions) and proper exponential backoff for rate limiting. ### 3. Monitor Deposit Instructions for Changes Account numbers and banking details can change over time. Always: - Subscribe to `ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE` webhooks - Periodically refresh deposit instructions for long-lived accounts - Update your UI/systems when instructions change ### 4. Never Use Reserve Accounts for Deposits Reserve accounts are internal system accounts and won't work for customer deposits. Always: - Create new accounts specifically for customer transactions - Use meaningful naming conventions (e.g., `CustomerName_Currency_SequenceNumber`) - Verify the `product_type` is `DEPOSIT`, not `CLIENT` ### 5. Handle Transaction States Properly Transactions progress through states: - **`PENDING`** - Detected but not yet approved (don't credit customer yet) - **`POSTED`** - Approved and settled (safe to credit customer) - **`CANCELLED`** - Transaction was cancelled (reverse any credits) Always wait for `TRANSACTION_POSTED` before considering funds available to the customer. ### 6. Link Transactions to Deposits Using category_id When querying transactions, use the deposit `id` as the `category_id` filter: ```bash GET /v1/accounts/deposits/{account_id}/transactions?category=DEPOSIT&category_id={deposit_id} ``` This ensures you're tracking the correct transactions for specific deposit requests. ### 7. Implement Proper Error Handling Common scenarios to handle: - Account not yet `OPEN` when requesting deposit instructions - Network timeouts when polling for status - Webhook delivery failures (implement retry logic) - Duplicate transaction notifications (use idempotency) ## Summary Let's review the account and funds management process: ### Core Workflow 1. **Authenticate** - Get your `AUTH_TOKEN` using OAuth2 2. **Open Account** - POST to [`/v1/accounts/deposits`](/api-docs/openapi/rail-spec#operation/openAccount) with customer details and asset type 3. **Verify Status** - GET [`/v1/accounts/deposits/{id}`](/api-docs/openapi/rail-spec#operation/getAccount) until status is `OPEN` 4. **Set Up Webhooks** - POST to [`/v1/subscriptions`](/api-docs/openapi/rail-spec#operation/createSubscription) for account and transaction events 5. **Get Deposit Instructions** - POST to [`/v1/deposits`](/api-docs/openapi/rail-spec#operation/createDeposits) with `deposit_type: "PUSH"` 6. **Track Deposits** - Listen for `TRANSACTION_PENDING` and `TRANSACTION_POSTED` webhooks, or poll transactions endpoint ### Key Takeaways - ✅ Always verify account status is `OPEN` before requesting deposit instructions - ✅ Use webhooks for real-time monitoring instead of polling - ✅ Subscribe to `ACCOUNT_DEPOSIT_INSTRUCTIONS_UPDATE` to catch instruction changes - ✅ Link transactions to deposits using `category_id` - ✅ Only credit customers after `TRANSACTION_POSTED` status - ✅ Never attempt deposits on reserve accounts - ✅ Implement proper error handling and retry logic ### API Endpoints Used | Endpoint | Purpose | Documentation | | --- | --- | --- | | `/v1/accounts/deposits` | Open new accounts and retrieve account lists | [Open Account](/api-docs/openapi/rail-spec#operation/openAccount), [Get Accounts](/api-docs/openapi/rail-spec#operation/getAccounts) | | `/v1/accounts/deposits/{id}` | Check individual account status and balance | [Get Account](/api-docs/openapi/rail-spec#operation/getAccount) | | `/v1/subscriptions` | Set up webhook subscriptions | [Create Subscription](/api-docs/openapi/rail-spec#operation/createSubscription) | | `/v1/deposits` | Get deposit instructions | [Create Deposit](/api-docs/openapi/rail-spec#operation/createDeposits) | | `/v1/accounts/deposits/{id}/transactions` | Track incoming deposits and transactions | [Get Transactions](/api-docs/openapi/rail-spec#operation/getTransactions) | To dive deeper into what you can do on the Rail platform, head to our [API documentation](/api-docs/openapi/rail-spec).