This document details the Balance Custody v1 Wallets API, offering endpoints to create, retrieve, update, and manage wallets, as well as initiate and track transactions specific to each wallet.
Below is a list of currencies generally supported by most APIs, unless specified otherwise. When interacting with the api, the lowercase ticker symbol must be used.
Bitcoin (btc)
Bitcoin Cash (bch)
Litecoin (ltc)
Dash (dash)
Ethereum (eth)
Ethereum Classic (etc)
Ripple (xrp)
Stellar Lumens (xlm)
Paxos (pax)
USD Coin (usdc)
Paxos Gold (paxg)
Stasis EURS (eurs)
QCAD (qcad)
BR.Mint (brlm)
Canadian Natural Dollar (cdag)
Monero (xmr)
AION (aion)
QCAD (qcad)
API URL
You will receive your wallet integration URL from your point of contact at Balance, and will look like:
YOUR_CUSTOM_SUBDOMAIN.balancecustody.ca
Authentication
Due to the nature of the information exposed, every endpoint in this API requires authentication.
For more information on authentication go to Authentication doc.
API Endpoints
For brevity, the curl examples below do not include headers. See the Authentication section above for required headers.
Response data is for example purposes only and does not represent real asset accounts.
GET /api/v1/wallets
List all wallets.
Accepted parameters:
Accepts the following GET parameters as part of the query string:
type
Optional. Specifies whether to return warm or cold wallets. If not specified, returns all wallets.
Possible values are:
warm - Warm wallets.
cold - Cold wallets.
created_since
Optional. If specified, returns wallets that were created after the given timestamp. If not specified, returns all wallets.
Values are UNIX timestamps (in seconds).
custom_id
Optional. Allows to search for wallets with a given Custom ID field. If not specified, returns all wallets.
Pagination
To request more results provide either a before or after parameter containing the cursor from the wallet you want data prior to or following. For example, to request data after the result in the example below: GET /api/v1/wallets?after=Mw==
A page_size parameter may be provided to control the size of the response. This must be between 1 and 100 and if omitted defaults to 10.
The owner structure will be returned if a wallet owner is declared.
GET /api/v1/wallets/:id
Show details for a single wallet. No parameters accepted.
NOTE: this endpoint will also return a "spendable_balance" field that can be used to query funds that are currently spendable (i.e. not locked in other pending or unconfirmed transactions).
Creates a new warm wallet. Content-Type header must be set to application/json.
Accepted parameters:
name - string, sets the name field of the warm wallet struct
description - string, sets the description field of the warm wallet struct
custom_id - string, sets the custom_id field of the warm wallet struct. This field is purely for your own internal tracking systems, and will not be queryable.
kind - string, specifies whether to create a cold or a warm wallet; accepted values are "cold" or "warm"; note that cold wallets are pre-generated in batches, and this API call may throw an error if no more cold wallets are available for use. In this scenario you will need to contact your custodian.
default_originator_entity - Travel Rule Entity struct; optional; see Regulatory Compliance Integration Docs for the definition of this field and examples for its use.
owner_entity_id - integer, sets the direct party owner of the new wallet.
Parameters must be serialized into a JSON object with the above fields set as top-level keys in the object. This JSON string must be passed in as part of request body.
Edits the basic metadata on an existing wallet. Content-Type header must be set to application/json.
Accepted parameters:
(Same parameters as in POST /api/v1/wallets)
name - string, sets the name field of the warm wallet struct
description - string, sets the description field of the warm wallet struct
custom_id - string, sets the custom_id field of the warm wallet struct
default_originator_entity - Travel Rule Entity struct; optional; see Regulatory Compliance Integration Docs for the definition of this field and examples for its use.
Parameters must be serialized into a JSON object with the above fields set as top-level keys in the object. This JSON string must be passed in as part of request body.
List all transactions for a given wallet. Includes internal and external transactions.
Internal transactions are defined as transactions between your Cold or Warm wallets managed by Balance Custody.
External transactions are defined as transactions that are originated externally, destined for your Cold or Warm wallets managed by Balance Custody.
Accepted parameters:
Accepts the following GET parameters as part of the query string:
status
Optional. Indicates the status of the transaction to query for. If not specified, returns all transactions.
Possible values are:
pending_approval - Transaction is in this state if your wallets are set up to require extra approvals before being signed and broadcast by the wallets.
approved - Transaction is in this state if it has been approved (or auto-approved if your wallets do not require extra approvals), but not yet signed and broadcast.
pending_generation - Transaction is in this state after a submitted transaction has received all required approvals, while our asynchronous workers are validating and generating transaction data for signing with the wallets.
completed - Transaction is in this state after it has been successfully signed and broadcast.
canceled - Transaction is in this state if its execution has been canceled through the UI.
failed - Transaction is in this state if it its execution failed at any of the steps. In this case the system administrators at Balance are notified and will contact you with next steps.
type
Optional. Indicates the type of the transaction to query for. If not specified, returns all transactions.
Possible values are:
internal - Transactions originating from your warm or cold wallets.
external - Incoming transactions originating from wallets outside your custody account.
completed_since
Optional. If specified, returns completed transactions only that were completed after the given timestamp. Completed transactions are defined as external transactions that are confirmed in a block, or internal transactions that have been successfully broadcast. If not specified, returns all transactions.
Values are UNIX timestamps (in seconds).
Pagination
To request more results provide either a before or after parameter containing the cursor from the transaction you want data prior to or following. For example, to request data after the result in the example below: GET /api/v1/wallets/1/transactions?after=MTI=
A page_size parameter may be provided to control the size of the response. This must be between 1 and 100 and if omitted defaults to 10.
Creates a new transaction with wallet_id being the source. Content-Type header must be set to application/json.
Accepted parameters:
Parameters must be serialized into a JSON object with the below fields set as top-level keys in the object. This JSON string must be passed in as part of request body.
Note that it is only possible to specify one transfer per currency inside a transaction request.
destination - a struct that defines the destination of the transaction. It is a polymorphic type, and the following types are accepted: wallet, external.
Example of wallet destination:
{
"destination": {
"type": "wallet",
"id": 2
}
}
Example of external destination using an existing external id:
amounts - a struct that specifies the amount (in native currency) that should be transferred.
Example of amounts for btc and eth:
{
"amounts": {
"btc": 0.123,
"eth": 4.567
}
}
fees - a dictionary that specifies the fee rate to be used when generating this transaction, where keys correspond to the lowercase currency ticker symbol, and values correspond to fee rates.
See Fee API docs for units of measurement in which fees are specified.
Fee rates can be specified as numbers (integer or float), as well as the following preset values: "slow", "medium", "fast". When preset values are specified they are automatically replaced with corresponding values from the Fee API.
Example of setting fees for btc to a custom value of 15.5 Sat/B and eth to a preset value of fast:
{
"fees": {
"btc": 15.5,
"eth": "fast"
}
}
Certain limitations apply to custom fee rate values:
Fee rates cannot be less than the "slow" preset value. This is to ensure transactions don't unnecessarily fail while broadcasting,
Fee rates cannot be more than 10x the "fast" preset value to guard against accidental conversion issues or other misuse.
Custom fees are not yet supported for Monero (xmr), but you can still use presets.
notes - a string that signifies your internal notes for this transaction. Optional.
NOTE: this note will NOT be included in the blockchain transactions for any currency. This is purely for your own internal tracking.
is_batched - (boolean) a flag that signifies whether a given transaction should be processed as part of a batch. Setting this flag to true will put the requested transaction into a batch generation queue after it has been approved (or immediately, if no approvals are required). If the queue reaches 50 transactions, or after 30 minutes (whichever is sooner), all transactions in this batch will be processed as a single on-chain transaction with each requested transaction as a separate output.
Note the following limitations to this option:
Only applies to transactions attempting a transfer of BTC, BCH, LTC, DASH. A 400-error will be returned if any other currency is specified in the request with this flag set to true.
Can only be set for single-currency transactions. A 400-error will be returned if the request specifies more than one currency for transfer with this flag set to true.
Only applies to transfers out of warm wallets. A 400-error will be returned if the request is attempting transfer out of a cold wallet with this flag set to true.
Only applies to non-sweep transfers. A 400-error will be returned if attempting a sweep with this flag set to true.
Note that batched transactions will return a transaction fee equal to the total transaction fee for the given on-chain transaction, divided by the number of transactions in the batch.
beneficiary_entity - specifies a beneficiary entity for regulatory compliance purposes.
This field is only required if Travel Rule enforcement is enabled on your account. Please talk to your Balance Custody account representative about whether it is enabled or disabled.
See Regulatory Compliance Integration Docs for a detailed description of the fields that are expected here, as well as examples of transactions submitted with beneficiary entity information.
Request
Example 1
Example of transaction that transfers 1.23 BTC and 4.56 ETH from warm wallet 1 to warm wallet 2:
Returns a transaction JSON struct. The transaction will be in the inactive state. Please use the GET /api/v1/wallets/:wallet_id/transactions/:transaction_id to poll for status updates. Be conservative with the polling rates.
Errors in this API will have a status code >= 400, and will come with an error message as part of a json-encoded body. E.g.
{
"error": "Invalid signature"
}
Status: 400
You will usually see this status code when you've missed a parameter, supplied an invalid value to one of the parameters, or if your request is somehow semanitcally invalid.
Examples of semantically invalid requests would be a transaction that is attempting to withdrawl an amount greater than the source wallet's balance.
Please refer to the error message for more details, as well as this doc to help debug issues.
Status: 401
You will usually see this status code when the server has failed to properly authenticate your request.
Content-Type header not set - you will see this error if your Content-Type header is not set. It is a required header.
Content-Type header must be application/json - you must set the value of the Content-Type header to application/json. No other value is supported at this time.
Date header not set - you will see this error if your Date header is not set. It is a required header.
"Failed to parse Date header" - the value of your Date header is improperly structured. Refer to this doc: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date
Date too far in the future - your date is set to more than 15 minutes in the future as compared to server date. Please check your clock.
Date is too old - your date is set to more than 15 minutes in the past. Check your clock, and re-generate this request.
Authorization header not set - you have failed to set the Authorization header. It is a required header.
Failed to parse Authorization header - you will see this error if the structure of your Authorization header is invalid. Refer to this document for an explanation.
Invalid signature - you will see this error if your signature is incorrect. Double check that your Access ID and Secret Key are set correctly. If you see this error, you can assume that the structure of your Authorization header is valid, and you have supplied other headers correctly.
Status: 403
You will usually see this error because you've reached some kind of a transaction limit set by your administrator.
Please refer to the included error message for more details.
Status 404
You will usually see this error in one of the following reasons:
You've entered a wrong URL
Your Access ID could not be found
A resource you're trying to access does not exist. This could be a wallet ID, destination wallet ID (for transactions), etc.
Status 500
You will only see this error if an unknown issue has occurred. Our system administrators will be automatically notified of this issue.
The recommended method for handling this issue would be to use a backoff scheme and retry this request at a later time.