On-ramp Use Case Build Guide

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

What is the On Ramp use case?

With the on ramp use case, you or your customers can safely and securely send in fiat, buy cryptocurrencies, stablecoins and hold or withdraw the digital currencies. We support a number of different digital assets today. Click here for the list of supported assets.

Fiat can be deposited using various different rails such as ACH, Fedwire, Swift, etc. The digital assets can be custodied on the Layer2 platform with qualified custodians such as banks, trusts or can be withdrawn to external custodial or non-custodial wallets.

path

Build Guide

This guide should take no longer than 10 minutes and will allow you to execute a Fiat On Ramp in Sandbox.

You'll open USD and USDC accounts for an already onboarded customer, add USD, exchange it to USDC and then withdraw the USDC to an external wallet.

NOTE: Given there is no testnet for fiat, there are some differences between Sandbox and Production. We will highlight those differences as we go along.

By the end of this guide you will have:

  1. Authenticated your request
  2. Created the fiat and crypto accounts for the customer
  3. Deposited the fiat
  4. Sold fiat for crypto
  5. Withdrawn crypto to an external wallet

Let’s go!

1. Authenticating your request

Every request you make to a Layer2 Financial API endpoint requires an AUTH_TOKEN. We secure our endpoints using standards based OAuth2 Client Credentials Grant and scopes. This makes authenticating secure and easy.

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=accounts:read+settlements:read+customers:read+customers:write+accounts:write+withdrawals:read+withdrawals:write+adjustments:read+adjustments:write+exchanges:read+exchanges:write+transfers:read+transfers:write+deposits:read+deposits:write+applications:read+applications: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:

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

The scopes we’ll need for this tutorial are:

  • customers:read and customers:write so we can create our customer and get information about them.
  • accounts:read and accounts:write so we can create our accounts and get information about them.
  • exchanges:read and exchanges:write so we can create an exchange operation and get information about it
  • deposits:read and deposits:write so we can create a deposit operation and get information about it
  • withrawals:read and withdrawals:write so we can create a withdrawal operation and get information about it

The full list of scopes are available here.

With that done, we can get on to setting up accounts for a individual customer we have pre-created for you: Daniel Lee, with a customer_id of DANIELLEE001. To learn how to create a customer, check out Applications.

2. Creating the fiat and crypto accounts

We need two accounts, a fiat deposit account and a crypto deposit account.

To create these two accounts we need:

  • The customer_id from above. For this example that is DANIELLEE001 .
  • An account_id for each account that will be the unique identifier for that specific account. Here we’ll use DANIELLEE001_USD.001 as our fiat account id and DANIELLEE001_USDC.001 for our crypto account id.
  • The product_id : This is the type of account to be opened. For the fiat account, it is DEPOSIT_BASIC . For crypto, it is DEPOSIT_BASIC . Different products have different capabilities. Click here to learn more about the various products we support.
  • The asset_type_id : The asset type that the accounts are going to use. Our fiat account is in USD, so the asset_type_id is FIAT_TESTNET_USD . For the USDC account, the asset_type_id is ETHEREUM_GOERLI_USDC . Click here to learn more about the various assets we support.

Creating our fiat account

For our fiat account, we’re going to call the /accounts/deposits endpoint:

Copy
Copied
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": "DANIELLEE001",
	"account_to_open": {
        "account_id": "DANIELLEE001_USD.001",
        "product_id": "DEPOSIT_BASIC",
        "asset_type_id": "FIAT_TESTNET_USD"
    }        
}'

The response contains the account_id that you passed in :

Copy
Copied
{
	data: {
		id: "DANIELLEE001_USD.001"
	}
}

Again, we can use that account_id and a GET request to the accounts/deposits/${account_id} endpoint to retrieve information about this account:

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

The response object will have the status of the account, product and asset type ids, and the current and available balance:

Copy
Copied
{
  "data": {
    "id": "DANIELLEE001_USD.001",
    "status": "OPEN",
    "asset_type_id": "FIAT_TESTNET_USD",
    "product_id": "DEPOSIT_BASIC",
    "current_balance": 0,
    "available_balance": 0
  }
}

Creating our crypto account

For our crypto account, we’re going to call the /accounts/deposits endpoint as well:

Copy
Copied
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": "DANIELLEE001",
	"account_to_open": {
        "account_id": "DANIELLEE001_USDC.001",
        "product_id": "DEPOSIT_BASIC",
        "asset_type_id": "ETHEREUM_GOERLI_USDC"
    }
}'

The response contains the account_id that you passed in :

Copy
Copied
{
	"data": {
		"id": "DANIELLEE_USDC.001"
	}
}

You can use that ACCOUNT_ID and a GET request to the /accounts/deposits/ endpoint to retrieve information about this account:

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

The response object will have the status of the account, product and asset type ids, and the current and available balance:

Copy
Copied
{
  "data": {
    "id": "DANIELLEE001_USDC.001",
    "status": "OPEN",
    "asset_type_id": "ETHEREUM_GOERLI_USDC",
    "product_id": "DEPOSIT_BASIC",
    "current_balance": 0,
    "available_balance": 0
  }
}

That’s it for creating our accounts. Now let's start transacting!

3. Depositing fiat

Next, we have to deposit fiat. you can do that by calling the deposits endpoint.

Copy
Copied
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": "DANIELLEE001_USD.001"
    }

}'

You will get back the following response with the fiat deposit instructions that you can supply to your customers. Once the fiat funds are deposited, the customer account will be credited.

You will notice 2 memo fields under the deposit_instructions. One is under the ACH instruction_type and the other is under the FEDWIRE instruction_type. Save one of those memo fields as you will need it to siumulate the deposit in Sandbox.

Copy
Copied
{
    "data": {
        "id": "90804565-effe-4fd4-8fb7-61b40eaa88c9",
        "status": "REQUESTED",
        "created_timestamp": "2023-02-20T12:09:26.63017-05:00",
        "destination_details": {
            "destination_account_id": "DANIELLEE001_USD.001",
            "asset_type_id": "FIAT_TESTNET_USD"
        },
        "deposit_instructions": [
            {
                "instruction_type": "ACH",
                "account_holder_name": "Joe Bloggs",
                "account_number": "9695859732",
                "account_routing_number": "715960587",
                "memo": "15218d1f-6651-4f62-812c-2e4aaa5c241c",
                "asset_type_id": "FIAT_TESTNET_USD"
            },
            {
                "instruction_type": "FEDWIRE",
                "account_holder_name": "Joe Bloggs",
                "account_number": "9695859732",
                "account_routing_number": "715960587",
                "account_holder_address": {
                    "unit_number": null,
                    "address_line1": "123 Sample St",
                    "address_line2": null,
                    "address_line3": null,
                    "city": "Boston",
                    "state": "MA",
                    "postal_code": "02135",
                    "country_code": "US"
                },
                "institution_address": {
                    "unit_number": null,
                    "address_line1": "1 Financial Place",
                    "address_line2": "Floor 34",
                    "address_line3": null,
                    "city": "Boston",
                    "state": "MA",
                    "postal_code": "02135",
                    "country_code": "US"
                },
                "memo": "ea947e78-50ba-40b0-8e6e-32345eeb2cab",
                "asset_type_id": "FIAT_TESTNET_USD"
            }
        ]
    }
}

To simulate the deposit in sandbox, Login to the Management UI using your provided organization id and credentials. Navigate to the Customers screen and click on the 'Create manual deposit' on the right.

Enter one of the memo entries from the above response object and 1000 as the amount you want to deposit.

path

Click on the 'Confirm' button and your funds will now be deposited within a few minutes into the account in sandbox.

path

After a few minutes, if you query the account using accounts/deposits/{ACCOUNT_ID} endpoint, you will see the current and available balance reflecing the $1,000 you just added.

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

The response object will reflect the available_balance of 1000.

Copy
Copied
{
  "data": {
    "id": "DANIELLEE001_USD.001",
    "status": "OPEN",
    "asset_type_id": "FIAT_TESTNET_USD",
    "product_id": "DEPOSIT_BASIC",
    "current_balance": 1000,
    "available_balance": 1000
  }
}

You can also check the account balance through the Management UI, by navigating to the customer and then the account for the customer.

Now that the USD is in the fiat account, lets exchange it for some USDC!

4. Exchanging fiat for crypto

To exchange the fiat to crypto, you have to call the /exchanges/market endpoint with a sell order, passing in the USD account as the source, and the USDC account as the destination.

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/exchanges/market' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
	"source_account_id": "DANIELLEE001_USD.001",
  	"destination_account_id": "DANIELLEE001_USDC.001",
  	"amount": 1000,
  	"action": "FIX_SOURCE"
}'

This will give us the response with the details of the REQUESTED exchange. Save the id of the exchange. You will need it for the EXCHANGE_ID in the next operation:

Copy
Copied
{
	"data": {
		**"id": "c3ac732e-fae0-4585-a7c3-71e24b8e7293"**, 
		"status": "REQUESTED", 
		"created_timestamp": "2022-11-11T09:32:14.450333", 
		"action": "FIX_SOURCE", 
		"source_details'": {
			"source_account_id": "DANIELLEE001_USD.001", 
			"asset_type_id": "FIAT_TESTNET_USD", 
			"amount_to_debit": 1000
		}, 
		"destination_details": {
			"destination_account_id": "DANIELLEE001_USDC.001", 
			'asset_type_id': 'ETHEREUM_GOERLI_USDC', 
			'amount_to_credit': 1000
		}
	}
}

We can use the id in the URL to accept this exchange:

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/exchanges/{EXCHANGE_ID}/accept' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
	"maximum_slippage": "0.001"
}'

We have to provide the maximum_slippage, which is the percentage difference between the initial quote from the /exchanges/quote endpoint and what you are willing to accept. You can learn more here.

If the exchange is accepted, you’ll get this response:

Copy
Copied
	"data": {
		**"id": "c3ac732e-fae0-4585-a7c3-71e24b8e7293"**, 
		"status": "ACCEPTED", 
		"created_timestamp": "2022-11-11T09:32:14.450333", 
		"action": "SELL", 
		"source_details'": {
			"source_account_id": "DANIELLEE001_USD.001", 
			"asset_type_id": "FIAT_TESTNET_USD", 
			"amount_to_debit": 1000
		}, 
		"destination_details": {
			"destination_account_id": "DANIELLEE001_USDC.001", 
			'asset_type_id': 'ETHEREUM_GOERLI_USDC', 
			'amount_to_credit': 1000
		}
	}

If it’s not accepted, you might have to increase your maximum_slippage.

The USDC funds are now in the USDC account, DANIELLEE001_USDC.001, but the funds have not yet settled. You can query account to check its balance with the /accounts/deposits endpoint.

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

This gives a response with the information we added above, the status of the account, and the current and available balance:

Copy
Copied
{
  "data": {
    "id": "DANIELLEE001_USDC.001",
    "status": "OPEN",
    "asset_type_id": "ETHEREUM_GOERLI_USDC",
    "product_id": "DEPOSIT_BASIC",
    "current_balance": 1000.000000000000000000,
    "available_balance": 0
  }
}

NOTE: the availablebalance above is showing as 0. In Sandbox, we don't have settlement on exchange yet. In Production, the `availablebalance` will show 0 until settlement completes.

Now that exchange is complete, lets see how to withdraw USDC funds to an external wallet.

5. Withdrawing crypto

As mentioned above, we don't have settlement in Sandbox yet. So you can't withdraw the USDC funds that you just bought. To test out the withdrawal functionality in Sandbox, you have to first add some USDC funds into the USDC deposit account.

Depositing USDC funds

You can add funds to your accounts by requesting an address for the account, via the deposits endpoint.

Copy
Copied
curl --location --request POST 'https://sandbox.layer2financial.com/api/v1/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "deposit_type": "PUSH",
	"deposit_destination": {
	  "destination_account_id": "DANIELLEE001_USDC.001"
  }
}'

This gives you a response object with the address. Click here to learn more about Deposits.

Copy
Copied
{
    "data": {
        "id": "d9b4cd0e-c66e-4540-9abd-55fa79833791",
        "status": "REQUESTED",
        "created_timestamp": "2023-03-05T14:56:32.316773-05:00",
        "destination_details": {
            "destination_account_id": "DANIELLEE001_USDC.001",
            "asset_type_id": "ETHEREUM_GOERLI_USDC"
        },
        "deposit_instructions": [
            {
                "instruction_type": "CRYPTO",
                "address": "0x9ED9961A87ba49511Cf522059df52e2a94eF188b",
                "blockchain": "ethereum",
                "network": "goerli",
                "asset_type_id": "ETHEREUM_GOERLI_USDC"
            }
        ]
    }
}

You can deposit funds into the address using any Goerli faucet, such as the Alchemy Goerli faucet (requires signup) or All That Node (no signup needed). You can also send us a note at support@layer2financial.com

Once you’ve deposited funds, you can check they are in the account by querying the accounts/deposits/{ACCOUNT_ID} endpoint again:

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

The current_balance should have changed to the amount you added to the account. The available_balance should now reflect amount you added as well:

Copy
Copied
{
  "data": {
    "id": "DANIELLEE001_USDC.001",
    "status": "OPEN",
    "asset_type_id": "ETHEREUM_GOERLI_USDC",
    "product_id": "DEPOSIT_BASIC",
    "current_balance": 1050.000000000000000000,
    "available_balance": 50.000000000000000000
  }
}

Once you see the available_balance updated, the USDC funds are now available to withdraw.

If the available_balance is not updated, the transaction is still going through all the blockchain confirmations, AML and Fraud checks. You can check on the status of the transactions by querying the accounts/deposits/{ACCOUNT_ID}/transactions endpoint. If you give it a few minutes, it will appear.

Withdrawing crypto funds to external wallet

Withdrawing funds has 3 steps: create a counterparty, setup the withdrawal and accept the withdrawal.

Create a Counterparty To create the counterparty, call the counterparties endpoint.

Set the blockchain_address to the address you want to withdraw to.

Copy
Copied
curl --location 'https://sandbox.layer2financial.com/api/v1/counterparties' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
    "customer_id": "DANIELLEE001",
    "description": "sample counterparty",
    "counterparty_type": "CRYPTO",
    "is_international": false,
    "supported_rails": ["CRYPTO"],
    "profile": {
        "name":"tarun",
        "address":{
            "country_code": "US"
        },
        "relationship_to_customer": "SELF"
    },
    "wallet_information": {
        "asset_type_id": "ETHEREUM_GOERLI_USDC",
        "blockchain_address": {BLOCKCHAIN_ADDRESS},
        "wallet_type": "OTHER",
        "institution_name": "SUPERCUSTODY",
        "institution_address": {
            "country_code":"US"
        }

    }
}'

A successful 200 response as follows will provide you the id, which is the counterparty_id you will need to setup the withdrawal.

Copy
Copied
{
    "data": {
        "id": "137df787-f903-4f0a-9ac0-f456d60bfb71"
    }
}

Setup the Withdrawal To setup the withdrawal, use the /withdrawals endpoint by passing the above id as the COUNTERPARTY_ID.

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

    "withdrawal_rail": "CRYPTO",
    "description": "Withdraw crypto",
    "source_account_id": "DANIELLEE001_USDC.001",
    "amount":"3",
    "destination_counterparty_id": "{COUNTERPARTY_ID}",
    "memo": "withdrawal"
}'

A 200 response will give you the id of the withdrawal. This will be the WITHDRAWAL_ID in the subsequent step.

Copy
Copied
{
    "data": {
        "id": "887804df-13c2-4019-835b-08c92ed77c72",
        "status": "REQUESTED"
    }
}

Accept Withdrawal Now its time to accept the withdrawal, by calling the withdrawals/{WITHDRAWAL_ID}/accept endpoint.

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

If its successful, you will get the following response.

Copy
Copied
{
	'data': {
		"id":"c67e81e5-3784-45d7-a2b9-b0c7f19a466f",
		"status":"ACCEPTED",
	}
}

And thats it, we take care of gas management, sweeping, etc behind the scenes.

Summary

Let’s review:

  1. Authenticate -Authenticate using the OAuth Endpoint to get the AUTH_TOKEN .
  2. Create accounts for the customer - Create a USD deposit account ( DEPOSIT_BASIC product type and FIAT_TESTNET_USD asset type) and USDC deposit account ( DEPOSIT_BASIC product type and ETHEREUM_GOERLI_USDC ) using the accounts/deposits endpoint .
  3. Send funds into Deposit account - Setup a deposit into the USD deposit account and get deposit instructions using the deposits endpoint . This will give you a memo in the deposit instructions. You will need this memo to simulate a fiat deposit in Sandbox, using the Management UI .
  4. Exchange to crypto - Setup the USD to USDC exchange using the exchanges endpoint . You have to accept the exchange using the exchanges/{EXCHANGE_ID}/accept endpoint .
  5. Withdraw crypo - Setup the USDC withdrawal to an external wallet using the withdrawals endpoint . You have to accept the withdrawal using the withdrawals/{WITHDRAWAL_ID}/accept endpoint

To dive deeper into what you can do on the Layer2 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.

© 2023 Layer2 Financial Inc. All Rights Reserved.