Withdrawals via API

If you haven't already, Sign Up for Sandbox Access to get your client ID and secret to work through this Build Guide!

What are Withdrawals?

Withdrawals allow customers to send funds from their Rail accounts to external bank accounts or crypto wallets. The withdrawal process involves creating a counterparty (the external destination), initiating the withdrawal, and accepting it for execution.

Rail supports withdrawals via multiple rails:

  • FIAT - Bank transfers (ACH, Wire, SWIFT, etc.)
  • CRYPTO - Blockchain withdrawals to external wallets

Auto-RFI (Request for Information)

Rail's Auto-RFI functionality automatically triggers document requests when withdrawals exceed certain thresholds. This ensures compliance requirements are met before processing large transactions.

How Auto-RFI Works:

  • Below Threshold - Withdrawal proceeds normally without additional documents
  • Above Threshold - Withdrawal enters CHANGES_REQUESTED status and requires documents (e.g., invoices) before it can be accepted

Core API Flow Sequence

The standard withdrawal flow follows these key steps:

  1. POST /v1/counterparties - Create a counterparty (external destination)
  2. POST /v1/withdrawals - Initiate the withdrawal
  3. GET /v1/withdrawals/{id}/status - Check withdrawal status (if Auto-RFI triggered)
  4. POST /v1/documents/{document_id} - Upload required documents (if needed)
  5. POST /v1/withdrawals/{id}/accept - Accept the withdrawal for execution

Build Guide

This guide covers two scenarios:

  1. Simple Withdrawal (Below Threshold)
  2. Withdrawal with Auto-RFI (Above Threshold)

By the end of this guide you will have:

  1. Authenticated your request
  2. Created a counterparty
  3. Initiated a withdrawal
  4. Handled Auto-RFI document requests (if triggered)
  5. Accepted the withdrawal
  6. Monitored withdrawal status

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:

Copy
Copied
curl --location --request POST 'https://auth.layer2financial.com/oauth2/ausbdqlx69rH6OjWd696/v1/token?grant_type=client_credentials&scope=counterparties:read+counterparties:write+withdrawals:read+withdrawals:write+accounts:read' \
--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:

Copy
Copied
{
    "token_type": "Bearer",
    "expires_in": 43200,
    "access_token": {AUTH_TOKEN},
    "scope": "counterparties:read counterparties:write withdrawals:read withdrawals:write accounts:read"
}

The scopes we'll need for this tutorial are:

  • counterparties:read and counterparties:write to create and manage counterparties
  • withdrawals:read and withdrawals:write to create and manage withdrawals
  • accounts:read to verify account balances

The full list of scopes are available here.


Scenario 1: Simple Withdrawal (Below Threshold)

This scenario covers a straightforward withdrawal that doesn't trigger Auto-RFI.

Step 1: Create a Counterparty

A counterparty represents the external destination where funds will be sent. You must create a counterparty before initiating a withdrawal.

Creating a Fiat Counterparty (Bank Account)

Create a counterparty for a US bank account using the /v1/counterparties endpoint:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/counterparties' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "customer_id": "INDIVIDUAL_CUSTOMER_001",
    "description": "John'\''s Chase Checking Account",
    "counterparty_type": "FIAT_US",
    "is_international": false,
    "supported_rails": ["ACH", "FEDWIRE"],
    "profile": {
        "name": "John Doe",
        "address": {
            "address_line1": "456 Bank Street",
            "city": "New York",
            "state": "NY",
            "postal_code": "10001",
            "country_code": "US"
        },
        "relationship_to_customer": "SELF"
    },
    "account_information": {
        "asset_type_id": "FIAT_TESTNET_USD",
        "account_number": "1234567890",
        "routing_number": "021000021",
        "account_type": "CHECKING"
    }
}'

The response includes the counterparty_id you'll need for the withdrawal:

Copy
Copied
{
    "data": {
        "id": "cpty_abc123456",
        "status": "ACTIVE"
    }
}

Important: Certain counterparty types require specific asset types in the account_information.asset_type_id field. For example, FIAT_CN counterparties must use Chinese Yuan asset types. See the Counterparties Guide for details.

Creating a Crypto Counterparty (Wallet Address)

Create a counterparty for a crypto wallet:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/counterparties' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "customer_id": "INDIVIDUAL_CUSTOMER_001",
    "description": "Customer'\''s Personal USDC Wallet",
    "counterparty_type": "CRYPTO",
    "is_international": false,
    "supported_rails": ["CRYPTO"],
    "profile": {
        "name": "John Doe",
        "address": {
            "country_code": "US"
        },
        "relationship_to_customer": "SELF"
    },
    "wallet_information": {
        "asset_type_id": "ETHEREUM_GOERLI_USDC",
        "blockchain_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
        "wallet_type": "OTHER",
        "institution_name": "Personal Wallet",
        "institution_address": {
            "country_code": "US"
        }
    }
}'

Response:

Copy
Copied
{
    "data": {
        "id": "cpty_xyz789012",
        "status": "ACTIVE"
    }
}

Step 2: Create a Withdrawal

Initiate a withdrawal using the /v1/withdrawals endpoint:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/withdrawals' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "withdrawal_rail": "ACH",
    "description": "Payment to vendor",
    "source_account_id": "CUSTOMER_USD_001",
    "amount": 500.00,
    "destination_counterparty_id": "cpty_abc123456",
    "memo": "Invoice #12345"
}'

Important: Use destination_counterparty_id (not just counterparty_id) and ensure withdrawal_rail is specified as it's a mandatory field.

The response includes the withdrawal_id and initial status:

Copy
Copied
{
    "data": {
        "id": "withdrawal_abc123",
        "status": "REQUESTED",
        "created_timestamp": "2023-11-20T14:32:18.123456Z",
        "source_details": {
            "source_account_id": "CUSTOMER_USD_001",
            "asset_type_id": "FIAT_TESTNET_USD",
            "amount_to_debit": 500.00
        },
        "destination_details": {
            "destination_counterparty_id": "cpty_abc123456",
            "withdrawal_rail": "ACH"
        }
    }
}

Step 3: Check Withdrawal Status

For withdrawals below the Auto-RFI threshold, the status will be REQUESTED. Check the status using the /v1/withdrawals/{id}/status endpoint:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_abc123/status' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response for a withdrawal below threshold:

Copy
Copied
{
    "data": {
        "id": "withdrawal_abc123",
        "status": "REQUESTED",
        "created_timestamp": "2023-11-20T14:32:18.123456Z",
        "withdrawal_validation_errors": [],
        "withdrawal_document_errors": []
    }
}

Since the status is REQUESTED and there are no validation or document errors, you can proceed to accept the withdrawal.

Step 4: Accept the Withdrawal

Accept the withdrawal to queue it for execution:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_abc123/accept' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response:

Copy
Copied
{
    "data": {
        "id": "withdrawal_abc123",
        "status": "ACCEPTED"
    }
}

Step 5: Monitor Withdrawal Status

The withdrawal will progress through various statuses:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_abc123' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response showing progression:

Copy
Copied
{
    "data": {
        "id": "withdrawal_abc123",
        "status": "PROCESSING",  // Then moves to COMPLETED or FAILED
        "created_timestamp": "2023-11-20T14:32:18.123456Z",
        "accepted_timestamp": "2023-11-20T14:33:00.000000Z",
        "source_details": {
            "source_account_id": "CUSTOMER_USD_001",
            "asset_type_id": "FIAT_TESTNET_USD",
            "amount_to_debit": 500.00
        },
        "destination_details": {
            "destination_counterparty_id": "cpty_abc123456",
            "withdrawal_rail": "ACH"
        }
    }
}

Scenario 2: Withdrawal with Auto-RFI (Above Threshold)

This scenario covers withdrawals that exceed the Auto-RFI threshold and require document uploads before acceptance.

Step 1: Create a Counterparty

Create a counterparty the same way as in Scenario 1:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/counterparties' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "customer_id": "INDIVIDUAL_CUSTOMER_001",
    "description": "Vendor Payment Account",
    "counterparty_type": "FIAT_US",
    "is_international": false,
    "supported_rails": ["FEDWIRE"],
    "profile": {
        "name": "ABC Corp",
        "address": {
            "address_line1": "789 Business Ave",
            "city": "San Francisco",
            "state": "CA",
            "postal_code": "94105",
            "country_code": "US"
        },
        "relationship_to_customer": "VENDOR"
    },
    "account_information": {
        "asset_type_id": "FIAT_TESTNET_USD",
        "account_number": "9876543210",
        "routing_number": "121000248",
        "account_type": "BUSINESS_CHECKING"
    }
}'

Response:

Copy
Copied
{
    "data": {
        "id": "cpty_vendor_123",
        "status": "ACTIVE"
    }
}

Step 2: Create a Withdrawal (Above Threshold)

Create a withdrawal for an amount that exceeds the Auto-RFI threshold:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/withdrawals' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "withdrawal_rail": "FEDWIRE",
    "description": "Large vendor payment",
    "source_account_id": "CUSTOMER_USD_001",
    "amount": 25000.00,
    "destination_counterparty_id": "cpty_vendor_123",
    "memo": "Invoice #INV-2023-1234"
}'

Response indicating Auto-RFI triggered:

Copy
Copied
{
    "data": {
        "id": "withdrawal_large_456",
        "status": "CHANGES_REQUESTED",
        "created_timestamp": "2023-11-20T15:00:00.123456Z",
        "source_details": {
            "source_account_id": "CUSTOMER_USD_001",
            "asset_type_id": "FIAT_TESTNET_USD",
            "amount_to_debit": 25000.00
        },
        "destination_details": {
            "destination_counterparty_id": "cpty_vendor_123",
            "withdrawal_rail": "FEDWIRE"
        }
    }
}

Notice: The status is CHANGES_REQUESTED instead of REQUESTED. This indicates that Auto-RFI has been triggered and documents are required.

Step 3: Get Document Requirements

Similar to the application onboarding process, check the withdrawal status to see which documents are required:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_large_456/status' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response showing required documents:

Copy
Copied
{
    "data": {
        "id": "withdrawal_large_456",
        "status": "CHANGES_REQUESTED",
        "created_timestamp": "2023-11-20T15:00:00.123456Z",
        "withdrawal_validation_errors": [],
        "withdrawal_document_errors": [
            {
                "document_id": "doc_withdrawal_001",
                "document_type": "INVOICE",
                "status": "MISSING",
                "description": "Invoice or receipt for this transaction"
            },
            {
                "document_id": "doc_withdrawal_002",
                "document_type": "CONTRACT",
                "status": "MISSING",
                "description": "Contract or agreement with vendor"
            }
        ]
    }
}

The withdrawal_document_errors array contains the document_ids you need for uploading documents.

Important: This is the same status endpoint used throughout the withdrawal lifecycle. It serves a dual purpose - providing status updates and identifying required documents (similar to how the application status endpoint works in customer onboarding).

Step 4: Upload Required Documents

Upload the required documents using the document_ids from the status response:

Copy
Copied
# Upload invoice
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/documents/doc_withdrawal_001' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--form 'file=@"/path/to/invoice.pdf"'

# Upload contract
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/documents/doc_withdrawal_002' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--form 'file=@"/path/to/contract.pdf"'

Each successful upload returns:

Copy
Copied
{
    "data": {
        "id": "doc_withdrawal_001",
        "status": "UPLOADED"
    }
}

Step 5: Verify Withdrawal is Ready

After uploading documents, check the withdrawal status again:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_large_456/status' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Once all documents are uploaded, the status returns to REQUESTED:

Copy
Copied
{
    "data": {
        "id": "withdrawal_large_456",
        "status": "REQUESTED",
        "created_timestamp": "2023-11-20T15:00:00.123456Z",
        "withdrawal_validation_errors": [],
        "withdrawal_document_errors": []
    }
}

Step 6: Accept the Withdrawal

Now that the status is REQUESTED and all documents are uploaded, you can accept the withdrawal:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/withdrawals/withdrawal_large_456/accept' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response:

Copy
Copied
{
    "data": {
        "id": "withdrawal_large_456",
        "status": "ACCEPTED"
    }
}

The withdrawal is now queued for execution and will be processed by Rail's banking partners.


Withdrawal Status Flow

Withdrawals progress through different statuses during their lifecycle:

Without Auto-RFI (Below Threshold)

REQUESTEDACCEPTEDPROCESSINGCOMPLETED / FAILED

With Auto-RFI (Above Threshold)

CHANGES_REQUESTED(upload documents)REQUESTEDACCEPTEDPROCESSINGCOMPLETED / FAILED

Status Meanings

Status Description Action Required
REQUESTED Withdrawal created and ready to accept Call /accept endpoint
CHANGES_REQUESTED Auto-RFI triggered, documents required Upload required documents via status endpoint
ACCEPTED Withdrawal accepted and queued for execution Monitor status for completion
PROCESSING Withdrawal being processed by banking partners Wait for completion
COMPLETED Withdrawal successfully processed None - funds sent
FAILED Withdrawal failed Review error details, may need to retry
CANCELLED Withdrawal cancelled None - no funds sent

Important: You cannot accept a withdrawal while it's in CHANGES_REQUESTED status. The withdrawal must return to REQUESTED status after all required documents are uploaded.


Managing Counterparties

Retrieve All Counterparties

List all counterparties for a customer:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/counterparties?customer_id=INDIVIDUAL_CUSTOMER_001' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response:

Copy
Copied
{
    "data": {
        "counterparties": [
            {
                "id": "cpty_abc123456",
                "customer_id": "INDIVIDUAL_CUSTOMER_001",
                "description": "John's Chase Checking Account",
                "counterparty_type": "FIAT_US",
                "status": "ACTIVE",
                "supported_rails": ["ACH", "FEDWIRE"]
            },
            {
                "id": "cpty_xyz789012",
                "customer_id": "INDIVIDUAL_CUSTOMER_001",
                "description": "Customer's Personal USDC Wallet",
                "counterparty_type": "CRYPTO",
                "status": "ACTIVE",
                "supported_rails": ["CRYPTO"]
            }
        ]
    }
}

Retrieve a Specific Counterparty

Get details for a single counterparty:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/counterparties/cpty_abc123456' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Update a Counterparty

Update counterparty details:

Copy
Copied
curl --location --request PUT 'https://sandbox.layer2financial.com/api/v1/counterparties/cpty_abc123456' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "description": "John'\''s Updated Checking Account",
    "profile": {
        "name": "John Doe",
        "address": {
            "address_line1": "789 New Address St",
            "city": "New York",
            "state": "NY",
            "postal_code": "10002",
            "country_code": "US"
        }
    }
}'

Delete a Counterparty

Remove a counterparty:

Copy
Copied
curl --location --request DELETE 'https://sandbox.layer2financial.com/api/v1/counterparties/cpty_abc123456' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'

Response:

Copy
Copied
{
    "data": {
        "id": "cpty_abc123456",
        "status": "DELETED"
    }
}

Withdrawal Best Practices

1. Verify Account Balance Before Creating Withdrawals

Always check that the source account has sufficient available balance:

Copy
Copied
curl --location --request GET 'https://sandbox.layer2financial.com/api/v1/accounts/deposits/CUSTOMER_USD_001' \
--header 'Authorization: Bearer {AUTH_TOKEN}'

Ensure available_balance is greater than or equal to the withdrawal amount.

2. Use the Status Endpoint Throughout the Lifecycle

The /v1/withdrawals/{id}/status endpoint serves multiple purposes:

  • Check if Auto-RFI was triggered
  • Get document IDs for required documents
  • Verify all requirements are met before accepting
  • Monitor withdrawal progress
Copy
Copied
# Always check status before attempting to accept
GET /v1/withdrawals/{id}/status

# If status is "REQUESTED" and no errors, proceed to accept
POST /v1/withdrawals/{id}/accept

3. Handle Auto-RFI Similar to Application Onboarding

The Auto-RFI process mirrors the application onboarding flow:

  1. Check status endpoint for required documents
  2. Upload documents using the provided document_id s
  3. Re-check status to verify all requirements are met
  4. Only then can you accept the withdrawal

4. Provide Meaningful Descriptions and Memos

Include clear descriptions and memos for audit trails and customer communication:

Copy
Copied
{
    "description": "Payment for Invoice #INV-2023-1234",
    "memo": "Q4 2023 Services - Net 30"
}

5. Match Asset Types Between Accounts and Counterparties

Ensure the asset_type_id of the source account matches the counterparty's expected asset type:

  • Fiat withdrawals: Account and counterparty must use the same fiat currency
  • Crypto withdrawals: Account and wallet must use the same blockchain and token

6. Set Up Webhook Subscriptions for Withdrawal Events

Monitor withdrawal lifecycle events in real-time:

Copy
Copied
# Subscribe to withdrawal events
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": "WITHDRAWAL_COMPLETED",
    "callback_url": "https://your-domain.com/webhooks/withdrawals"
}'

Recommended withdrawal webhooks:

  • WITHDRAWAL_REQUESTED - Withdrawal initiated
  • WITHDRAWAL_ACCEPTED - Withdrawal accepted for processing
  • WITHDRAWAL_PROCESSING - Withdrawal being processed
  • WITHDRAWAL_COMPLETED - Withdrawal successfully sent
  • WITHDRAWAL_FAILED - Withdrawal failed
  • WITHDRAWAL_CANCELLED - Withdrawal cancelled

7. Implement Proper Error Handling

Handle common withdrawal errors:

Copy
Copied
try {
    const withdrawal = await createWithdrawal({
        amount: 25000,
        destination_counterparty_id: counterpartyId
    });
    
    const status = await getWithdrawalStatus(withdrawal.id);
    
    if (status.status === 'CHANGES_REQUESTED') {
        // Auto-RFI triggered - handle document upload
        await handleDocumentRequirements(status.withdrawal_document_errors);
    } else if (status.status === 'REQUESTED') {
        // Ready to accept
        await acceptWithdrawal(withdrawal.id);
    }
} catch (error) {
    if (error.code === 'INSUFFICIENT_BALANCE') {
        // Handle insufficient funds
    } else if (error.code === 'INVALID_COUNTERPARTY') {
        // Handle invalid counterparty
    }
    // Log and notify
}

8. Store Counterparties for Repeat Withdrawals

Save frequently used counterparties to simplify repeat withdrawals:

Copy
Copied
// First time - create and store counterparty
const counterparty = await createCounterparty({...});
await database.saveCounterparty(customerId, counterparty.id);

// Subsequent withdrawals - reuse counterparty
const storedCounterpartyId = await database.getCounterparty(customerId);
await createWithdrawal({
    destination_counterparty_id: storedCounterpartyId,
    amount: 1000
});

Summary

Let's review the withdrawal process:

Simple Withdrawal (Below Threshold)

  1. Authenticate - Get your AUTH_TOKEN using OAuth2
  2. Create Counterparty - POST to /v1/counterparties with destination details
  3. Create Withdrawal - POST to /v1/withdrawals with destination_counterparty_id and withdrawal_rail
  4. Check Status - GET /v1/withdrawals/{id}/status to verify status is REQUESTED
  5. Accept Withdrawal - POST to /v1/withdrawals/{id}/accept to queue for execution
  6. Monitor Progress - Track withdrawal through PROCESSING to COMPLETED

Withdrawal with Auto-RFI (Above Threshold)

  1. Authenticate - Get your AUTH_TOKEN using OAuth2
  2. Create Counterparty - POST to /v1/counterparties
  3. Create Withdrawal - POST to /v1/withdrawals
  4. Check Status - GET /v1/withdrawals/{id}/status - status will be CHANGES_REQUESTED
  5. Upload Documents - POST to /v1/documents/{document_id} for each required document
  6. Re-check Status - Verify status has returned to REQUESTED
  7. Accept Withdrawal - POST to /v1/withdrawals/{id}/accept
  8. Monitor Progress - Track withdrawal through PROCESSING to COMPLETED

Key Takeaways

  • ✅ Create counterparties before initiating withdrawals
  • ✅ Use destination_counterparty_id (not counterparty_id ) in withdrawal requests
  • ✅ Always specify withdrawal_rail as it's mandatory
  • ✅ Match asset types between accounts and counterparties
  • ✅ Use the status endpoint to check for Auto-RFI document requirements
  • ✅ Handle CHANGES_REQUESTED status similar to application onboarding
  • ✅ Upload all required documents before attempting to accept
  • ✅ Set up webhooks to monitor withdrawal progress
  • ✅ Verify account balance before creating withdrawals

API Endpoints Used

Endpoint Purpose Documentation
/v1/counterparties Create and manage external destinations Create Counterparty, Counterparties Guide
/v1/withdrawals Create withdrawal requests Create Withdrawal
/v1/withdrawals/{id}/status Check withdrawal status and document requirements Get Withdrawal Status
/v1/withdrawals/{id}/accept Accept withdrawal for execution Accept Withdrawal
/v1/documents/{document_id} Upload required documents Upload Document

To dive deeper into what you can do on the Rail platform, head to our API documentation.

Contact Us - We'd love to hear your thoughts, and you can contact the team via slack, website or email support@layer2financial.com.

© 2024 Rail. All Rights Reserved.