Wallet as a Service 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 Wallet as a Service Use Case?
The wallet as a service use case enables you to embed digital asset accounts into your experience. Rapidly onboard and enable you and your customers to safely and securely custody and exchange stablecoins, cryptocurrencies, or fiat.
Build Guide
This guide should take no longer than 10 minutes. By the end of this tutorial you will have:
- Authenticated your Request
- Created a new customer
- Created an account for that customer
- Generated a deposit address for the account
- Deposited funds into the account
- Transferred funds between two accounts
- Sold these funds through an exchange
Once you are done with this quick start guide, head over to our our API documentation to continue diving deeper.
1. Authenticating your requests
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:
curl --location --request POST 'https://auth.layer2financial.com/oauth2/ausbdqlx69rH6OjWd696/v1/token?grant_type=client_credentials&scope=customers:read+customers:write+accounts:read+accounts:write+transfers:read+transfers:write+exchanges:read+exchanges: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:
{
"token_type":"Bearer",
"expires_in":43200,
"access_token": AUTH_TOKEN,
"scope":"customers:read customers:write transfers:read transfers:write accounts:write accounts:read exchanges:read exchanges:write"
}
The scopes we’ll need for this tutorial are:
-
customers:read
andcustomers:write
so we can create our customer and get information about them. -
accounts:read
andaccounts:write
so we can create our accounts and get information about them. -
transfers:read
andtransfers:write
so we can create our transfers and get information about them. -
exchanges:read
andexchanges:write
so we can create our exchanges and get information about them
The full list of scopes are available here.
2. Creating your first customer
The customer is the individual or corporation End User that is using your service.
We are going to create a corporate customer using the customers
endpoint (You create an individual customer with the same API endpoint).
Note: The
customers
endpoint is for use by regulated entities. If you need Layer2 to perform KYC/KYB on your behalf, you will need to use theapplications
endpoint for onboarding. For this build guide, we will skip onboarding via theapplications
endpoint. See Applications for more information.
To create a corporate customer, the data you need is:
-
The customer
id
. This is the unique identifier of your customer within the Layer2 system. It must be unique to you. -
The
customer_type
. This isCORPORATION
. -
The
registered_name
of the corporation. This is the actual registered company name of the customer.
In this example, we’re going to onboard a new customer called Quorum, whose registered name is Quorum, Inc. So we’ll set up their id
as ‘QUORUM001’ and their registered_name
as ‘Quorum, Inc’.
Note: The
id
doesn’t have to include the company name. It just has to be unique. You can use any current customer identifier from your own system. See External Entity Identifiers for more information.
Each of those attributes can be added to a data object and POST
ed to the customers
API endpoint.
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/customers' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"id": "QUORUM001",
"customer_type": "CORPORATION",
"registered_name": "Quorum, Inc"
}'
A successful request will return a status code of 200
and a response object with the id
of the new customer:
{
'data': {
'id': 'QUORUM001'
}
}
Once you’ve created a customer, you can retrieve information about that customer at any time using a GET
request to the same endpoint, appended with their CUSTOMER_ID
:
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/customers/QUORUM001' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'
The response object:
{
data: {
id: "QUORUM001",
customer_type: "CORPORATION",
status: "ACTIVE",
registered_name: "Quorum, Inc",
registered_address: {
unit_number: null,
address_line1: null,
address_line2: null,
address_line3: null,
city: null,
state: null,
postal_code: null,
country_code: null
}
}
}
3. Creating an Account
Accounts are the center of the Layer2 platform. They allow your customers to trade and hold fiat and other digital assets. They abstract away the complexity of wallets and keys.
Here we’re going to create an ETH account, but the process is the same whether your are creating a fiat account or a digital asset account
To create an account for your customer you need:
-
The
customer_id
from above. For this example that is ‘QUORUM001’. -
An
account_id
: This is the unique identifier for the account. As with the customer id, this can be an External Entity Identifier from your own system. For this example, we’ll use ‘QUORUM001.001’ as our account id. -
The
product_id
: This is the type of account to be opened. In this guide, we will be working with Deposit accounts. So, we are going to be using theBASIC_DEPOSIT
for the crypto account ANDBASIC_DEPOSIT_FIAT
for the fiat account. Click here to learn more about Accounts. -
The
asset_type_id
: The asset type that this account is going to use. Theasset_type_id
is in the form of{$BLOCKCHAIN}_{$NETWORK}*_*{$CURRENCY_CODE}
. We are going to open an account for ETH so this isETHEREUM_GOERLI_ETH_T
. So for USD, this will beFIAT_TESTNET_USD_T
.
With all that information, we can add it to our data object and POST
it to our accounts API endpoint:
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/accounts/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"customer_id": "QUORUM001",
"account_to_open": {
"account_id": "QUORUM001.001",
"product_id": "BASIC_DEPOSIT",
"asset_type_id": "ETHEREUM_GOERLI_ETH_T"
}
}'
If all goes well, we’ll get a 200
and this response:
{
data: {
id: "QUORUM001.001"
}
}
If we need to query this specific account again we can use the same endpoint with GET
and the ACCOUNT_ID
appended:
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/accounts/deposits/QUORUM001.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:
{
data: {
id: "QUORUM001.001",
status: "OPEN",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
product_id: "BASIC_DEPOSIT",
current_balance: 0,
available_balance: 0
}
}
As with the customers API, calling the accounts
endpoint without appending an ACCOUNT_ID
will return data on all accounts across all customers:
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/accounts/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
The response:
{
data: {
accounts: [
{
id: "QUORUM001.001",
status: "OPEN",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
product_type: "DEPOSIT",
product_id: "BASIC_DEPOSIT",
customer_id: "QUORUM001",
current_balance: 0,
available_balance: 0
},
...
]
},
}
Currently, we only have one account. We’ll change that soon. But first, let’s add funds to this account.
4. Generating a deposit address
You can add funds to your accounts by requesting an address for the account, via the deposits
endpoint.
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"deposit_type": "PUSH",
"deposit_destination": {
"destination_account_id": "QUORUM001.001"
}
}'
This gives you a response object with the address
. Click here to learn more about Deposits.
{
"data": {
"id": "d9b4cd0e-c66e-4540-9abd-55fa79833791",
"status": "REQUESTED",
"created_timestamp": "2023-03-05T14:56:32.316773-05:00",
"destination_details": {
"destination_account_id": "QUORUM001.001",
"asset_type_id": "ETHEREUM_GOERLI_ETH_T"
},
"deposit_instructions": [
{
"instruction_type": "CRYPTO",
"address": "0x9ED9961A87ba49511Cf522059df52e2a94eF188b",
"blockchain": "ethereum",
"network": "goerli",
"asset_type_id": "ETHEREUM_GOERLI_USDC_T"
}
]
}
}
5. Depositing your funds
To add funds, all we need is the address
from above. With the address
, you can deposit USDC into this account using any Goerli faucet, such as the Alchemy Goerli faucet (requires signup) or All That Node (no signup needed). You can also send 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:
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/accounts/deposits/QUORUM001.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:
{
"data": {
"id": "QUORUM001.001",
"status": "OPEN",
"asset_type_id": "ETHEREUM_GOERLI_ETH_T",
"product_id": "BASIC_DEPOSIT",
"current_balance": 0.2,
"available_balance": 0
}
}
If the available_balance
is showing 0
as above, the transaction is still going through all the AML and Fraud checks. You can check on the status of the transactions by querying the transactions
endpoint.
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/accounts/deposits/QUORUM001.001/transactions' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'
The response object will tell us what we need to know about our transactions:
{
'data': {
'transactions': [
{
'id': 'd01c36a3-78ef-41f0-8209-455dd0b46680',
'value': 0.2,
'transaction_date': '2022-11-09T09:46:55.519763',
'transaction_posted_date': '2022-11-09T09:46:55.519763',
'transaction_status': 'PENDING',
'description': 'TRANSFER_IN',
'transaction_type': 'TRANSFER_IN'
}
]
}
}
As we can see, our transaction_status
is still PENDING
. Once the transaction is ACCEPTED, we’ll see the funds in our available_balance
. You may find that your transaction was already POSTED
by the time you have checked. That’s ok - we’re just moving faster than we planned!
{
data: {
id: "QUORUM001.001",
status: "OPEN",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
product_id: "BASIC_DEPOSIT",
current_balance: 0.2,
available_balance: 0.2
}
}
6. Transfering funds between accounts
We now have available funds in our account. Let’s spread the wealth and transfer some to another account.
First, we’ll need another account. Customers can have multiple accounts of the same or different product type and asset type. We’ll create another account for CUSTOMER_ID
QUORUM001:
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/accounts/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"customer_id": "QUORUM001",
"account_to_open": {
"account_id": "QUORUM001.002",
"product_id": "BASIC_DEPOSIT",
"asset_type_id": "ETHEREUM_GOERLI_ETH_T"
}
}'
We’ll get the response object with the new account id:
{
data: {
id: "QUORUM001.002"
}
}
Note: Here we’re transferring funds between two accounts for the same customer. But you can also transfer funds between accounts of different customers just as easily—all you ever need are the
ACCOUNT_ID
s. You can find out more what’s needed to transfer between accounts in the documentation here.
Now we are set to transfer funds between the two accounts:
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/transfers' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"source_account_id": "QUORUM001.001",
"destination_account_id": "QUORUM001.002",
"amount": 0.1,
"description": "ETHEREUM_GOERLI_ETH_T"
}'
The data we get back shows that the transfer has been REQUESTED
correctly:
{
data: {
id: "38c24bb4-c117-4bb2-951f-efd69c83a7d3",
status: "REQUESTED",
created_timestamp: "2022-11-07T21:56:20.254871",
valid_until: "2022-11-07T22:06:20.233949",
source_details: {
source_account_id: "QUORUM001.001",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
amount_to_debit: 0.1
},
destination_details: {
destination_account_id: "QUORUM001.002",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
amount_to_credit: 0.1
}
}
}
For the transfer to be executed, the receiving account has to accept the transfer. To do so, you pass the TRANSFER_ID
to the transfers API accept
endpoint:
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/transfers/{TRANSFER_ID}/accept' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'
Then the status should show ACCEPTED
:
{
data: {
id: "38c24bb4-c117-4bb2-951f-efd69c83a7d3",
status: "ACCEPTED"
}
}
Query our second account and we’ll see the funds:
{
data: {
id: "QUORUM001.002",
status: "OPEN",
asset_type_id: "ETHEREUM_GOERLI_ETH_T",
product_id: "BASIC_DEPOSIT",
current_balance: 0.1,
available_balance: 0.1
}
}
7. Exchanging funds
Customers can buy and sell funds on the Layer2 platform through the exchanges
endpoint. Exchanges are like transfers, but between accounts in different currencies (asset types).
Let’s set up a third account, but this time in USD:
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/accounts/deposits' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"customer_id": "QUORUM001",
"account_to_open": {
"account_id": "QUORUM001.003",
"product_id": "BASIC_DEPOSIT_FIAT",
"asset_type_id": "FIAT_TESTNET_USD_T"
}
}'
Once that account is set up we can SELL
our 0.1 ETH in our QUORUM001.002 to our QUORUM001.003 account. We start by getting a quote.
curl --location --request POST 'https://alpha.layer2financial.dev/api/v1/exchanges/quote' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"source_account_id": "QUORUM001.002",
"destination_account_id": "QUORUM001.003",
"amount": 0.1,
"action": "SELL"
}'
This will give us the response with the details of the REQUESTED
exchange:
{
'data': {
'id': 'c3ac732e-fae0-4585-a7c3-71e24b8e7293',
'status': 'REQUESTED',
'created_timestamp': '2022-11-11T09:32:14.450333',
'action': 'SELL',
'source_details': {
'source_account_id': 'QUORUM001.002',
'asset_type_id': 'ETHEREUM_GOERLI_ETH_T',
'amount_to_debit': 0.1
},
'destination_details': {
'destination_account_id': 'QUORUM001.003',
'asset_type_id': 'FIAT_TESTNET_USD_T',
'amount_to_credit': 127.12
}
}
}
We can use the id
in the URL to accept this exchange:
curl --location --request POST 'https://alpha.layer2financial.dev/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:
"data": {
"id": "c3ac732e-fae0-4585-a7c3-71e24b8e7293",
"status": "ACCEPTED",
"created_timestamp": "2022-11-11T10:31:59.728741",
"action": "SELL",
"source_details": {
"source_account_id": "QUORUM001.002",
"asset_type_id": "ETHEREUM_GOERLI_ETH_T",
"amount_to_debit": 0.1
},
"destination_details": {
"destination_account_id": "QUORUM001.003",
"asset_type_id": "FIAT_TESTNET_USD_T",
"amount_to_credit": 125.43
}
}
}
If it’s not accepted, you might have to increase your maximum_slippage
.
You can now query the ACCOUNT_ID
QUORUM001.003 to see the balance
curl --location --request GET 'https://alpha.layer2financial.dev/api/v1/accounts/deposits/QUORUM001.003' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--header 'Content-Type: application/json'
And that’s it. You have everything you need to set up each of your customers on the Layer2 platform and allow them to open accounts, and receive, transfer, and buy and sell funds.
Summary
Let’s review:
-
Authenticate using the OAuth Endpoint to get the
AUTH_TOKEN
. -
Set up a customer with the
customers
endpoint . Then use thecustomer_id
to query or update information. -
Open an account with the
accounts/deposits
endpoint . Then use theaccount_id
to query or update information. -
Generate a
address
to deposit funds into the new account using thedeposits
endpoint . -
Deposit funds using external faucets to the
address
and query the balance of the the account using theaccounts/deposits/{account_id}
endpoint -
Transfer funds between accounts using the
transfers
endpoint . -
Exchange funds with the
exchanges
endpoint and theBUY
andSELL
actions.
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 here or email us at sales@layer2financial.com.