# Create currency balance
Source: https://docs.busha.io/api-reference/balances/create-currency-balance
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/balances
Creates a new balance for managing funds in a specific currency.
# Get balance details
Source: https://docs.busha.io/api-reference/balances/get-balance-details
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/balances/{id_or_code}
# List all balances
Source: https://docs.busha.io/api-reference/balances/list-all-balances
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/balances
Retrieves all account balances with their current status.
# Retrieve details of a specific currency
Source: https://docs.busha.io/api-reference/currencies/retrieve-details-of-a-specific-currency
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/currencies/{code}
Fetches detailed information about a specific currency using its unique code. This includes details such as network support, decimal precision, and transaction limits.
# Retrieve supported currencies
Source: https://docs.busha.io/api-reference/currencies/retrieve-supported-currencies
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/currencies
Retrieves a list of all supported currencies along with their basic details. This endpoint can be used to display available currencies in wallets or APIs requiring currency data.
# Create a new customer
Source: https://docs.busha.io/api-reference/customers/create-a-new-customer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/customers
Creates a new customer entry in the system. The required fields depend on the `type` of customer being created ('individual' or 'business').
# Delete a customer
Source: https://docs.busha.io/api-reference/customers/delete-a-customer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml delete /v1/customers/{id}
Delete a customer by their unique ID
# Export Customers
Source: https://docs.busha.io/api-reference/customers/export-customers
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/customers/export
Export customers to a csv file
# Generate KYC link for a customer
Source: https://docs.busha.io/api-reference/customers/generate-kyc-link-for-a-customer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/customers/{id}/kyc-link
Generate a KYC verification link for an individual customer
# Get a customer by ID
Source: https://docs.busha.io/api-reference/customers/get-a-customer-by-id
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/customers/{id}
Retrieve a specific customer by their unique ID
# List Business Industries
Source: https://docs.busha.io/api-reference/customers/list-business-industries
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/customers/industries
List all business industries
# List Customers
Source: https://docs.busha.io/api-reference/customers/list-customers
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/customers
List all customers in created for the business
# Share customer token
Source: https://docs.busha.io/api-reference/customers/share-customer-token
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/customers/{id}/token-share
Token sharing.
# Update a customer
Source: https://docs.busha.io/api-reference/customers/update-a-customer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml put /v1/customers/{id}
Update the details of an existing customer
# Verify a customer
Source: https://docs.busha.io/api-reference/customers/verify-a-customer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/customers/{id}/verify
Verify the identity and information provided by a customer
# Generate presigned upload URL
Source: https://docs.busha.io/api-reference/files/generate-presigned-upload-url
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/files
Generates a presigned URL for uploading files directly to storage
# Get customer growth
Source: https://docs.busha.io/api-reference/insights/get-customer-growth
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/insights/customers/growth
Returns the business customer growth trend: new and cumulative customer counts per interval bucket (UTC), plus a summary with the growth rate versus the immediately preceding period of equal length.
# Get transaction breakdown
Source: https://docs.busha.io/api-reference/insights/get-transaction-breakdown
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/insights/transactions/breakdown
Returns transaction counts within the requested date range grouped by the requested dimension, with percentage shares. Currency is optional; when omitted, all currencies are counted.
# Get transaction trends
Source: https://docs.busha.io/api-reference/insights/get-transaction-trends
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/insights/transactions/trends
Returns an inflow/outflow/net cash flow time series for completed transactions in the requested currency, bucketed by the requested interval (UTC). Buckets with no activity are zero-filled.
# Introduction
Source: https://docs.busha.io/api-reference/introduction
Introductory essay for integrating with Busha
The **Busha API** is designed to provide businesses with tools for borderless financial transactions and operations, enabling modern, global money management. It serves as the backbone for facilitating:
* Creation and management of multi-currency balances
* Retrieval of real-time cryptocurrency rates
* Substantial data insights for business owners
## Authentication
All API requests require a **Bearer Token** for authentication, passed in the `Authorization` header.
Your authorization value is a base64 encoded value of your api key and your secret key.
You can obtain API tokens via your Busha user or business account. Authentication is mandatory to ensure secure and authorized interactions with the API.
The API keys from the dashboard provides a base64 encoding of the your authorization tokens.
Your generated Key should look like this:
`VURtNXhWcHueantkpaiewjo0S044MWsadfojienuoxRTiWDJaeWJaTGxxanZ3Ym10OU1RZnVWajVW=`
Example Header:
```curl theme={null}
Authorization: Bearer VURtNXhWcHueantkpaiewjo0S044MWsadfojienuoxRTiWDJaeWJaTGxxanZ3Ym10OU1RZnVWajVW=
```
## Error Handling
Standardized error responses ensure predictable interactions. Errors are detailed for easy debugging and understanding:
| **Error Code** | **HTTP Status Code** | **Description** |
| --------------------- | -------------------- | ---------------------------------- |
| `bad_request` | 400 | Invalid input or malformed request |
| `unauthorized` | 401 | Invalid or missing authentication |
| `not_found` | 404 | Resource not found |
| `service_unavailable` | 503 | Server error |
Basic Error Example:
```json theme={null}
{
"error": {
"name": "bad_request",
"message": "Invalid input data"
}
}
```
Schema Error Body Example:
```json theme={null}
{
"error": {
"name": "bad_request",
"message": "Invalid input data"
},
"schema": {
"reason": "The request body is defined as an object. However, it does not meet the schema requirements of the specification",
"fix": "Ensure that the object being submitted, matches the schema correctly"
}
}
```
Field Error Body Example:
```json theme={null}
{
"error": {
"name": "bad_request",
"message": "Invalid input data"
},
"fields": {
"field1": [
{
"reason": "The request body is defined as an object. However, it does not meet the schema requirements of the specification",
},
],
"field2": [
{
"reason": "The request body is defined as an object. However, it does not meet the schema requirements of the specification",
}
],
}
}
```
## Pagination
Pagination uses cursors provided as:
The API supports **cursor-based pagination** for endpoints with large datasets. Pagination uses a `next_cursor` and `previous_cursor` returned in the response.
Example Response Format:
```json theme={null}
{
"current_entries_size": 10,
"next_cursor": "base64_cursor_value",
"previous_cursor": "base64_previous_cursor_value"
}
```
## Rate Limiting
Rate limits determine how many API calls can be made in a rolling minute. This ensures fair and optimized use of system resources.
The rate limits allowed by each resource will be provided with the header:
```curl theme={null}
x-rate-limit 100
```
If this header does not exist, then the rate limit is set at a default 100 req/min
Requests exceeding the allocated quota will receive a `429 Too Many Requests` response.
## Common Parameters
Common parameters enhance consistency across endpoints:
| **Parameter Name** | **Location** | **Description** | **Example** |
| ------------------ | ------------ | ------------------------ | ------------------------ |
| `X-BU-PROFILE-ID` | Header | User profile identifier | `BUS_qwejinoiuiqw93ejjw` |
| `id` | Path | Unique NanoID identifier | `dpt_jweqafajsndiun34fd` |
| `cursor` | Query | Pagination cursor | `base64_cursor_string` |
#### Paginated Response Example
```json theme={null}
{
"status": "success",
"message": "Data retrieved",
"pagination": {
"next_cursor": "value_for_next_page",
"current_entries_size": 20
},
"data": [...]
}
```
# Get a merchant by public key
Source: https://docs.busha.io/api-reference/miscellaneous/get-a-merchant-by-public-key
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/merchants
Get a merchant
# Get deposit address
Source: https://docs.busha.io/api-reference/miscellaneous/get-deposit-address
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/addresses/{code}
Get an address for a currency
# Get virtual bank account
Source: https://docs.busha.io/api-reference/miscellaneous/get-virtual-bank-account
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/virtual_bank_accounts/{code}
Get a virtual bank account for a currency
# Get virtual bank account terms
Source: https://docs.busha.io/api-reference/miscellaneous/get-virtual-bank-account-terms
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/virtual_bank_accounts/{code}/terms
Get the terms and conditions for a virtual bank account by currency code
# List banks resource
Source: https://docs.busha.io/api-reference/miscellaneous/list-banks-resource
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/banks
Returns a list of all banks and their bank codes
# Look up users addresses
Source: https://docs.busha.io/api-reference/miscellaneous/look-up-users-addresses
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/pay/{username}
Returns a user's addresses based on currency and network
# Regenerate deposit address
Source: https://docs.busha.io/api-reference/miscellaneous/regenerate-deposit-address
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/addresses/regenerate
Regenerate an address for a network
# Returns a list of countries
Source: https://docs.busha.io/api-reference/miscellaneous/returns-a-list-of-countries
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/countries
Returns a list of countries and their supported payment channels
# Validate payment destination
Source: https://docs.busha.io/api-reference/miscellaneous/validate-payment-destination
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/validate
validates a payment destination is valid
# List trading pairs
Source: https://docs.busha.io/api-reference/pairs/list-trading-pairs
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/pairs
Retrieves all available trading pairs with their current rates.
# Activate a draft invoice
Source: https://docs.busha.io/api-reference/paymentlinks/activate-a-draft-invoice
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/payments/links/{id}/activate
Transitions an invoice from draft status to active and sends email notification to customer
# Create a payment link
Source: https://docs.busha.io/api-reference/paymentlinks/create-a-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/payments/links
Create a payment link
# Create a payment request for payment link
Source: https://docs.busha.io/api-reference/paymentlinks/create-a-payment-request-for-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/payments/links/{id}/requests
Create a payment request for payment link
# Delete a payment link
Source: https://docs.busha.io/api-reference/paymentlinks/delete-a-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml delete /v1/payments/links/{id}
Delete a payment link
# List payment links
Source: https://docs.busha.io/api-reference/paymentlinks/list-payment-links
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/payments/links
List payment links
# List payment requests for payment link
Source: https://docs.busha.io/api-reference/paymentlinks/list-payment-requests-for-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/payments/links/{id}/requests
List payment requests for payment link
# Retrieve a payment link
Source: https://docs.busha.io/api-reference/paymentlinks/retrieve-a-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/payments/links/{id}
Retrieve a payment link
# Update a payment link
Source: https://docs.busha.io/api-reference/paymentlinks/update-a-payment-link
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml patch /v1/payments/links/{id}
Update a payment link
# Create a payment request
Source: https://docs.busha.io/api-reference/paymentrequests/create-a-payment-request
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/payments/requests
Create a payment request
# Finalize a payment request
Source: https://docs.busha.io/api-reference/paymentrequests/finalize-a-payment-request
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/payments/requests/{id}/finalize
Finalize a payment request
# List payment requests
Source: https://docs.busha.io/api-reference/paymentrequests/list-payment-requests
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/payments/requests
List payment requests
# Retrieve a payment request
Source: https://docs.busha.io/api-reference/paymentrequests/retrieve-a-payment-request
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/payments/requests/{id}
Retrieve a payment request
# Activate pledge
Source: https://docs.busha.io/api-reference/pledges/activate-pledge
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/{id}/activate
Confirm that the beneficiary credit agreement is active. Requires an OAuth pledge grant with beneficiary context.
# Add pledge items
Source: https://docs.busha.io/api-reference/pledges/add-pledge-items
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/{id}/items
Add more customer-authorized assets to an active pledge. Requires an OAuth pledge grant with beneficiary context.
# Cancel pledge liquidation
Source: https://docs.busha.io/api-reference/pledges/cancel-pledge-liquidation
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/{id}/liquidations/{liquidation_id}/cancel
Cancel a pending liquidation before processing starts. Requires an OAuth pledge grant with beneficiary context.
# Create pledge
Source: https://docs.busha.io/api-reference/pledges/create-pledge
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges
Create a pledge from a valid quote and lock the quoted items. Requires an OAuth pledge grant with beneficiary context.
# Create pledge quote
Source: https://docs.busha.io/api-reference/pledges/create-pledge-quote
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/quotes
Preflight a multi-asset pledge lock without moving funds. Requires an OAuth pledge grant with beneficiary context.
# Get pledge
Source: https://docs.busha.io/api-reference/pledges/get-pledge
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/pledges/{id}
Retrieve pledge state, items, and lifecycle events visible to the selected profile or OAuth pledge grant.
# List pledges
Source: https://docs.busha.io/api-reference/pledges/list-pledges
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/pledges
List pledges visible to the selected profile, or to the authenticated OAuth pledge grant when beneficiary context is present.
# Release pledge items
Source: https://docs.busha.io/api-reference/pledges/release-pledge-items
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/{id}/release
Release all or part of the pledged assets back to the customer. Requires an OAuth pledge grant with beneficiary context.
# Request pledge liquidation
Source: https://docs.busha.io/api-reference/pledges/request-pledge-liquidation
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/pledges/{id}/liquidations
Request notice-period liquidation under the stored pledge mandate. Requires an OAuth pledge grant with beneficiary context.
# Create a new Quote
Source: https://docs.busha.io/api-reference/quotes/create-a-new-quote
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/quotes
Create Quote
# Create Unauthenticated Quotes
Source: https://docs.busha.io/api-reference/quotes/create-unauthenticated-quotes
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/quotes/unauthenticated
Create Unauthenticated Quote
# Get Quote
Source: https://docs.busha.io/api-reference/quotes/get-quote
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/quotes/{id}
Returns a single quote by it's unique ID
# List Payment Options
Source: https://docs.busha.io/api-reference/quotes/list-payment-options
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/quote/payment_options
List Fiat Payment Options
# List Quotes
Source: https://docs.busha.io/api-reference/quotes/list-quotes
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/quotes
List Quotes
# Create a recipient
Source: https://docs.busha.io/api-reference/recipients/create-a-recipient
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/recipients
Create a new recipient for transfers.
# Delete a recipient
Source: https://docs.busha.io/api-reference/recipients/delete-a-recipient
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml delete /v1/recipients/{id}
Delete a specific recipient
# List recipients
Source: https://docs.busha.io/api-reference/recipients/list-recipients
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/recipients
Retrieve a list of all recipients
# Resolves a bank account
Source: https://docs.busha.io/api-reference/recipients/resolves-a-bank-account
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/recipients/resolve-bank-account
Resolves a bank account for bank transfers
# Retrieve a recipient
Source: https://docs.busha.io/api-reference/recipients/retrieve-a-recipient
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/recipients/{id}
Get details of a specific recipient
# List stocks
Source: https://docs.busha.io/api-reference/stocks/list-stocks
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks
# Market status
Source: https://docs.busha.io/api-reference/stocks/market-status
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/market-status
# Stock activity
Source: https://docs.busha.io/api-reference/stocks/stock-activity
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/activities
A page of the authenticated profile's stock fills (buys and sells) across every symbol, newest first. Optionally narrowed to one action and/or a set of symbols.
# Stock detail
Source: https://docs.busha.io/api-reference/stocks/stock-detail
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/{symbol}
# Stock holdings
Source: https://docs.busha.io/api-reference/stocks/stock-holdings
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/portfolio
Every open stock position for the authenticated profile, valued at the current display (mid) token price. The spread is what a trade costs, not part of what is owned, so it is not applied here.
# Stock OHLC candles
Source: https://docs.busha.io/api-reference/stocks/stock-ohlc-candles
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/{symbol}/ohlc
# Stock position detail
Source: https://docs.busha.io/api-reference/stocks/stock-position-detail
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/portfolio/{symbol}
One position for the authenticated profile plus a page of the fills behind it, newest first.
# Top movers
Source: https://docs.busha.io/api-reference/stocks/top-movers
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/stocks/movers
Top gainers and losers by 24h percent change over listed symbols with a fresh enough price to rank.
# Get transaction
Source: https://docs.busha.io/api-reference/transactions/get-transaction
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/transactions/{id}
Retrieves a transactions
# List transactions
Source: https://docs.busha.io/api-reference/transactions/list-transactions
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/transactions
Returns a list of transactions
# Create transfer
Source: https://docs.busha.io/api-reference/transfers/create-transfer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml post /v1/transfers
Create a transfer object
# Get transfer
Source: https://docs.busha.io/api-reference/transfers/get-transfer
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/transfers/{id}
Retrieves a transfer
# List transfers
Source: https://docs.busha.io/api-reference/transfers/list-transfers
https://raw.githubusercontent.com/bushaHQ/openapi/refs/heads/main/openapi-spec.yaml get /v1/transfers
Gets all transfers
# Changelog
Source: https://docs.busha.io/changelog/index
Review historical changes and latest updates to the Busha Developer Documentation.
## August 2026
### 2026/08/27
Added a new endpoint to generate a hosted KYC verification link for an individual customer, letting the customer complete their own identity verification without you needing to collect and submit documents on their behalf.
**New endpoint:** `POST /v1/customers/{customer_id}/kyc-link`
**Example request:**
```bash theme={null}
curl -X POST "https://api.busha.so/v1/customers/CUS_xxx/kyc-link" \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json"
```
**Example response:**
```json theme={null}
{
"status": "success",
"message": "KYC link generated successfully",
"data": {
"url": "https://in.sumsub.com/websdk/p/sbx_j0t47nDxjmWDw503"
}
}
```
Share the returned `url` with your customer to let them complete verification directly. Once submitted, the customer's status updates the same way as document-based verification, moving from `inactive` to `in_review` and then `active` or `rejected`.
### 2026/08/24
Individual customers can now have a Bank Verification Number (BVN) added as part of `identifying_information` when creating or updating a customer.
**What's new:**
* New `bvn` type available in the `identifying_information` array
* BVN is optional for standard KYC, but required if you want to generate a virtual NGN bank account for the customer via `GET /v1/virtual_bank_accounts/{code}`
**Example payload:**
```json theme={null}
"identifying_information": [
{
"type": "bvn",
"number": "12345678901",
"country": "NG"
}
]
```
If a virtual bank account is requested for a customer without a BVN on file, the API returns `err_bvn_verification_required`. Add a BVN at customer creation, or afterward via `PUT /v1/customers/{customer_id}`.
**Updated guide:**
* [`Create an individual customer`](/guides/customers/create-individual)
## July 2026
### 2026/07/06
NIN verification is now a non-document flow. When verifying customers with a Nigerian National Identification Number (NIN), you no longer need to upload ID document images only the NIN number and a selfie are required.
**What changed:**
* **Removed:** `image_front` and `image_back` from the `national-id` object in `identifying_information`
* **Unchanged:** Passport verification and selfie requirements remain the same
**Updated guides:**
* [`Create an individual customer`](/guides/customers/create-individual)
* [`Verify identity`](/guides/customers/verify-identity)
**Reference payload:**
```json theme={null}
"identifying_information": [
{
"type": "national-id",
"number": "12345678901",
"country": "NG"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
```
## May 2026
### 2026/05/22
Busha Pay is now available as a native mobile SDK for React Native, iOS (Swift), Android (Kotlin), and Flutter, enabling crypto checkout directly within your mobile app.
* **React Native** — `@busha/pay-react-native` via npm or GitHub releases
* **iOS (Swift)** — `BushaPay` via Swift Package Manager
* **Android (Kotlin)** — `pay-android` via JitPack
* **Flutter** — `busha_pay` via pub.dev
**New guide:** [Accept Stablecoin with Mobile SDK](/guides/accepting-stablecoin-payments/mobile-sdk)
### 2026/05/06
* **Page:**
[`guides/payment-requests/create-first-payment`](/guides/payment-requests/create-first-payment)
* Removed the `dry_run` parameter from the `POST /v1/payments/requests`
endpoint. The field is no longer accepted or documented. Developers previously
using `dry_run: true` to preview payment request calculations should remove
the field from their request bodies requests will now be created and persisted
regardless.
## April 2026
### 2026/04/26
Added `quote_id` as a query parameter on the `GET /v1/transfers` endpoint, allowing you to retrieve the transfer associated with a specific quote.
**New query parameter:**
* `quote_id`: Filter transfers by the quote used to create them.
**Example:**
```bash theme={null}
curl -X GET "https://api.busha.io/v1/transfers?quote_id=QUO_xxxxxxxxxx" \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
**Example response:**
```json theme={null}
{
"status": "success",
"message": "Fetched transfers successfully",
"data": [
{
"id": "TRF_xxxxxxxxxx",
"quote_id": "QUO_xxxxxxxxxx",
...
}
]
}
```
## March 2026
### 2026/03/27
Introduced the `kyc_status` field in the `GET /customers` and `GET /customers/{id}` endpoints to allow businesses to check the KYC verification status of their customers.
New field:
* `kyc_status`: Returns the current KYC verification state of the customer. Possible values: `pending`, `in_review`, `verified`, `rejected`.
For example:
```json theme={null}
{
"id": "CUS_9z8y7x6w5v4u3t2s1r",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone_number": "+234 8012345678",
"kyc_status": "verified", // customer has completed KYC verification
"created_at": "2026-03-15T10:30:00Z"
}
```
In the response above, the `kyc_status` field shows that the customer has successfully completed KYC verification, allowing you to programmatically gate features or transaction limits based on their verification level.
### 2026/03/06
Introduced `deposit.success` webhook event to notify you when deposits are made to your static bank account.
**Use case:**
This event enables you to automatically convert incoming fiat deposits to your preferred stablecoin using the Quotes and Transfers endpoints.
**How it works:**
1. Customer deposits funds to your static bank account
2. `deposit.success` webhook event is triggered
3. Your system receives the webhook notification
4. You can automatically create a quote and transfer to convert the deposited amount to crypto
**Event payload example:**
```json theme={null}
{
"business_id": "bus_1a2b3c4d5e6f7g8h9i0j",
"event": "deposit.success",
"data": {
"id": "289bb2c1-b4fc-46df-b313-6945a8d23615",
"profile_id": "CUS_9z8y7x6w5v4u3t2s1r",
"amount": "5900.00",
"fee": "100.00",
"total": "6000.00",
"currency": "NGN",
"reference": "Resf12dx3c333333",
"channel": "bank_transfer",
"status": "COMPLETED",
"source_account_name": "Test Oluwatoni",
"source_bank_name": "Bank of World",
"source_account_number": "1234567890",
"reserved_account_id": "8d1c58b0-9143-410b-be61-805e8421c466",
"account_name": "ARTAX DIGITAL / Oluwatoni Test",
"account_number": "4051483002",
"created_at": "2025-02-26T11:29:02.336285+01:00"
}
}
```
**Key fields:**
* `amount`: The deposited amount (after fees)
* `fee`: The deposit fee charged
* `total`: The total amount deposited (before fees)
* `currency`: The currency of the deposit (e.g., NGN, KES)
* `status`: Deposit status (COMPLETED)
* `profile_id`: The customer ID who made the deposit
**Important:** To start receiving this event, you must re-register your webhook:
* Navigate to Settings → Developer Tools → Webhooks in your Busha dashboard
* Delete your existing webhook endpoint
* Create a new webhook and select the deposit event along with any other events you want to subscribe to
* Save your new webhook configuration
### 2026/03/04
Updated KYC requirements for individual customers. The `identifying_information` field now requires a selfie image instead of a selfie video.
**What changed:**
* **Removed:** `documents` array with selfie video requirement
* **Added:** Selfie image object in `identifying_information` array
* **Required combinations:** Customers must provide ONE of the following:
* Passport + number + image\_front + selfie image
* National ID + number + image\_front + image\_back + selfie image
**Identifying information object structure:**
```json theme={null}
"identifying_information": [
{
"type": "passport",
"number": "passport-number",
"country": "NG",
"image_front": "",
"image_back": ""
},
{
"type": "selfie",
"image_front": "",
"number": "",
"country": "NG"
}
]
```
## February 2026
### 2026/02/27
Added request logs feature to help businesses monitor and debug API activity. View detailed logs of API requests made to Busha directly from your dashboard.
**What you can see:**
* **Status code:** HTTP response status
* **HTTP method:** Request type
* **Endpoint:** The specific API endpoint called
* **Request ID:** Unique identifier for each request
* **Timestamp:** Date of each request
**Features:**
* **Search by Request ID:** Quickly find specific requests using the search bar
* **Filter options:** Narrow down logs by various criteria
* **Pagination:** Browse through your request history
* **Auto-refresh:** Logs update automatically as new requests are made
**How to access:**
Navigate to **Settings → Developer Tools → Request Logs** in your Busha dashboard.
### 2026/02/24
Introduced the `reversal_policy` field in quote object to control how cancelled/failed transfers are refunded.
**New field:**
* **`reversal_policy`**: An optional field set to `"conversion_only"` to refund the original source amount to the source balance in the event of a transfer failure. The field accepts `conversion_only` value for now.
For example:
```json theme={null}
{
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"reversal_policy": "conversion_only", // refund the transfer back to USDT if the quote transfer fails.
"pay_in": {
"type": "address",
"network": "SOL"
},
"pay_out": {
"type": "bank_transfer",
"recipient_id": "625syssysts8388"
}
}
```
In the quote above, the originating transfer will refund the source amount of 100 to the business source (USDT) balance if the transfer goes into a refunded state either from cancellation or failure to complete its lifecycle.
### 2026/02/23
Added webhook event history and replay functionality in the Busha dashboard. Businesses can now view, monitor, and resend past webhook events for the last 21 days.
**Key features:**
* **Event History:** View all webhook events from the last 21 days with full request/response details
* **Manual Replay:** Resend failed or missed webhook events directly from the dashboard
* **Search & Filter:** Find specific events by reference ID, status, category, or date
* **Delivery Tracking:** Monitor webhook delivery success and failure rates
* **Debugging Tools:** Inspect exact payloads sent for troubleshooting integration issues
**How to access:**
Navigate to **Settings** → **Developer Tools** → **Webhooks** in your Busha dashboard, then click on a webhook to view its activity log.
### 2026/02/18
All API endpoints now return a unique request identifier in the response headers under `X-Request-Id`. Request IDs help track specific API calls and expedite issue resolution when contacting Busha support.
**Key details:**
* **Header name:** `X-Request-Id`
* **Format:** `req_` prefix followed by alphanumeric string (e.g., `req_JfPBXEC5rLHc`)
* **Availability:** All endpoints
* **Retention:** 21 days
**New guide:** [`guides/request-id/request-id`](/guides/request-id/request-id) explains how to capture request IDs in your code and when to use them for debugging.
Use request IDs to provide precise details when reporting API errors or unexpected behavior to Busha support.
### 2026/02/10
* **Page:**
[`guides/recipients/create-and-manage`](/guides/recipients/create-and-manage)
* Deleted legacy code examples that no longer match the current API surface. -
Removed the deprecated `X-BU-VERSION` header from sample requests so
developers copying the guide use headers the API actually accepts.
### 2026/02/04
Added the `transfer.funds_refunded` event in [`guides/webhooks/webhook-events`](/guides/webhooks/webhook-events). This event fires when funds are returned to the sender's balance after a transfer fails (for example, an invalid payout destination or network delivery issue).
| Event | Trigger | Key Payload Fields |
| ------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `transfer.funds_refunded` | Funds are refunded to the balance following a failed transfer. | `status: "funds_refunded"`, `fees` (array with refund-related fees), `pay_out` (original destination details), `updated_at` |
Use this event to automatically reconcile balances, notify users that their funds have been returned, or trigger retry logic.
Introduced token sharing capability to enable seamless customer onboarding across platforms using Sumsub. Businesses can now import pre-verified KYC data from partner platforms, eliminating duplicate verification processes.
**Key details:**
* **Endpoint:** `POST /v1/customers/{id}/token-share`
* **Integration:** Requires Sumsub account with Reusable KYC feature enabled
* **Supported:** Individual customers only (not business customers)
**New guide:** [`guides/token-sharing/token-sharing`](/guides/token-sharing/token-sharing) covers the complete flow from Sumsub token generation to importing verified customer data into Busha.
This feature significantly reduces customer onboarding friction for businesses operating across multiple platforms.
* **Page:** [`overview/transfers`](/overview/transfers) - Added
`funds_refunded` to the list of possible transfer statuses so integrators know
this terminal state exists.
## January 2026
### 2026/01/30
* **Page:**
[`guides/getting-started/setup-sandbox`](/guides/getting-started/setup-sandbox)
* Updated the sandbox account registration link to point to the current
developer console URL. - Refreshed the onboarding steps so new integrators
land on the correct dashboard and can generate API keys without confusion.
### 2026/01/28
* **Page:**
[`guides/customers/transactions-on-behalf`](/guides/customers/transactions-on-behalf)
* Adjusted usage scenarios and parameter descriptions to stay accurate for
delegated (on-behalf-of) transaction flows. - Ensured code samples reflect the
latest required headers and request body shape.
### 2026/01/27
The following guides under `guides/customers/` have been completely rewritten to improve clarity and align with current API behavior:
| Page | Summary of Changes |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`Create business`](/guides/customers/create-business) | Expanded KYB (Know Your Business) workflow documentation, added field-by-field explanations for required business registration data, and included sample request/response payloads that match the live API. |
| [`Create individual`](/guides/customers/create-individual) | Overhauled KYC (Know Your Customer) instructions with step-by-step guidance, clearer document-upload requirements, and updated example payloads reflecting actual field names and validation rules. |
| [`Verify identity`](/guides/customers/verify-identity) | Clarified the verification lifecycle (from `inactive` → `in_review` → `active` or `rejected`), documented each possible status transition, and explained how to interpret verification outcomes programmatically. |
Added comprehensive webhook coverage in [`guides/webhooks/webhook-events`](/guides/webhooks/webhook-events). The following four events are now documented with full sample payloads, trigger conditions, and recommended handling patterns:
| Event | Trigger | Key Payload Fields |
| --------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- |
| `customer.verification.in_review` | Customer submits verification documents and review begins. | `status: "in_review"`, `level: "0"`, `updated_at` |
| `customer.verification.active` | Review succeeds; customer is fully verified. | `status: "active"`, `level: "1"`, `updated_at` |
| `customer.verification.rejected` | Review fails due to invalid or incomplete documents. | `status: "rejected"`, `rejection_reason`, `level: "0"`, `updated_at` |
| `customer.verification.inactive` | Verification reverted (compliance issue, suspension, etc.). | `status: "inactive"`, `level: "0"`, `updated_at` |
Each event follows the standard webhook envelope (`business_id`, `event`, `data`) and can be used to automate customer onboarding workflows, surface rejection reasons to end-users, or trigger compliance alerts.
# USD Conversions
Source: https://docs.busha.io/examples/buy-usd
Buy and sell USD with fiat or cryptocurrency using Busha's API.
This example shows you how to buy and sell USD with either fiat currency or cryptocurrency using Busha's API.
## Use Cases
* Convert local currency to USD
* Convert stablecoins to USD
* Convert USD to local currency
* International payments
* USD savings and liquidity management
***
## Buy USD
### Buy USD with Fiat
### Buy USD with 50,000 NGN via Bank Transfer
Create a quote with temporary bank account funding:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "USD",
"source_amount": "50000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_gCcLjJ0P0uEc",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "NGN",
"target_currency": "USD",
"source_amount": "50000",
"target_amount": "33.48543819",
"rate": {
"product": "USDNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USD"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"type": "temporary_bank_account"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_gCcLjJ0P0uEc",
"status": "pending",
"expires_at": "2026-01-23T11:34:17.175170741Z",
"created_at": "2026-01-23T11:04:17.175146315Z",
"updated_at": "2026-01-23T11:04:17.175146315Z"
}
}
```
Use the quote ID to get temporary bank details:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_gCcLjJ0P0uEc"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_JSaOYnl7Sla0",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_gCcLjJ0P0uEc",
"description": "Bought USD",
"sub_description": "With NGN",
"source_currency": "NGN",
"target_currency": "USD",
"source_amount": "50000",
"target_amount": "33.48543819",
"trade": "buy",
"rate": {
"product": "USDNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USD"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2026-01-23T11:37:32.289498887Z",
"recipient_details": {
"account_name": "BIBAGE TECHNOLOGIES LTD || Liverppol Business",
"account_number": "0327318166",
"bank_code": "090614",
"bank_name": "Aella Microfinance Bank",
"email": "ajibola@busha.co"
},
"type": "temporary_bank_account"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-23T11:07:31.197428968Z",
"updated_at": "2026-01-23T11:07:31.197429043Z"
}
}
```
**Important:** Transfer exactly ₦50,000 to the provided bank account before the expiration time. The USD will be credited to your balance once payment is confirmed.
Monitor the transfer to confirm the purchase completed successfully:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_JSaOYnl7Sla0 \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_JSaOYnl7Sla0",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_gCcLjJ0P0uEc",
"description": "Bought USD",
"sub_description": "With NGN",
"source_currency": "NGN",
"target_currency": "USD",
"source_amount": "50000",
"target_amount": "33.48543819",
"trade": "buy",
"rate": {
"product": "USDNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USD"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2026-01-23T11:37:32.289498887Z",
"recipient_details": {
"account_name": "BIBAGE TECHNOLOGIES LTD || Liverppol Business",
"account_number": "0327318166",
"bank_code": "090614",
"bank_name": "Aella Microfinance Bank",
"email": "ajibola@busha.co"
},
"type": "temporary_bank_account"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 3,
"current_step": 3,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your NGN payment",
"timestamp": "2026-01-23T11:07:34.553579Z"
},
{
"step": 2,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "We received your NGN Payment",
"timestamp": "2026-01-23T11:07:34.553579Z"
},
{
"step": 3,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your USD has been added to your wallet.",
"timestamp": "2026-01-23T11:07:34.65765Z"
}
]
},
"created_at": "2026-01-23T11:07:31.197428Z",
"updated_at": "2026-01-23T11:07:35.404245Z"
}
}
```
#### Other Examples
**Buy USD with NGN from Balance**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "USD",
"source_amount": "50000",
"pay_in": {
"type": "balance"
}
}'
```
***
### Buy USD with Crypto
### Convert 100 USDT to USD from Balance
Create a quote to see the exchange rate:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "USD",
"source_amount": "100",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_zqGjq5VI4Dyu",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USDT",
"target_currency": "USD",
"source_amount": "100",
"target_amount": "99.6",
"rate": {
"product": "USDTUSD",
"rate": "0.996",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USD"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_zqGjq5VI4Dyu",
"status": "pending",
"expires_at": "2026-01-20T09:48:40.822804422Z",
"created_at": "2026-01-20T09:18:40.822779472Z",
"updated_at": "2026-01-20T09:18:40.822779472Z"
}
}
```
Use the quote ID to finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_zqGjq5VI4Dyu"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_O7MHNJocNQaN",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_zqGjq5VI4Dyu",
"description": "Sold USDT",
"sub_description": "For USD",
"source_currency": "USDT",
"target_currency": "USD",
"source_amount": "100",
"target_amount": "99.6",
"trade": "sell",
"rate": {
"product": "USDTUSD",
"rate": "0.996",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USD"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-20T09:33:01.915628818Z",
"updated_at": "2026-01-20T09:33:01.915628873Z"
}
}
```
Monitor the transfer to confirm completion:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_O7MHNJocNQaN \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_O7MHNJocNQaN",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_zqGjq5VI4Dyu",
"description": "Sold USDT",
"sub_description": "For USD",
"source_currency": "USDT",
"target_currency": "USD",
"source_amount": "100",
"target_amount": "99.6",
"trade": "sell",
"rate": {
"product": "USDTUSD",
"rate": "0.996",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USD"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Crypto Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your USD has been added to your wallet."
}
]
},
"created_at": "2026-01-20T09:33:01.915628Z",
"updated_at": "2026-01-20T09:33:02.456789Z"
}
}
```
### Convert 100 USDC to USD via Crypto Deposit
Create a quote with crypto deposit address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDC",
"target_currency": "USD",
"source_amount": "100",
"pay_in": {
"type": "address",
"network": "TRX"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_7so9hb74wusK",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USDC",
"target_currency": "USD",
"source_amount": "100",
"target_amount": "99.6",
"rate": {
"product": "USDCUSD",
"rate": "0.996",
"side": "sell",
"type": "FIXED",
"source_currency": "USDC",
"target_currency": "USD"
},
"fees": [],
"pay_in": {
"network": "TRX",
"type": "address"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_7so9hb74wusK",
"status": "pending",
"expires_at": "2026-01-20T15:38:44.561315603Z",
"created_at": "2026-01-20T15:08:44.56129334Z",
"updated_at": "2026-01-20T15:08:44.56129334Z"
}
}
```
Use the quote ID to get the deposit address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_7so9hb74wusK"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_UELotkEEfes6",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_7so9hb74wusK",
"description": "Sold USDC",
"sub_description": "For USD",
"source_currency": "USDC",
"target_currency": "USD",
"source_amount": "100",
"target_amount": "99.6",
"trade": "sell",
"rate": {
"product": "USDCUSD",
"rate": "0.996",
"side": "sell",
"type": "FIXED",
"source_currency": "USDC",
"target_currency": "USD"
},
"fees": [],
"pay_in": {
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"expires_at": "2026-01-20T16:10:01.640438Z",
"network": "TRX",
"type": "address"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-20T15:10:01.555002867Z",
"updated_at": "2026-01-20T15:10:01.555002935Z"
}
}
```
**Important:** Send exactly 100 USDC (TRC20) to the address `TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm` before the expiration time. The USD will be credited to your balance once the deposit is confirmed on-chain.
#### Other Examples
**Buy USD with USDC from Balance**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDC",
"target_currency": "USD",
"source_amount": "100",
"pay_in": {
"type": "balance"
}
}'
```
***
## Sell USD
### Sell USD for Fiat
### Convert 50 USD to NGN
Create a quote to see the exchange rate:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "50",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_6T9lPmqMSPPt",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "50",
"target_amount": "80363.5",
"rate": {
"product": "USDNGN",
"rate": "1607.27",
"side": "sell",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_6T9lPmqMSPPt",
"status": "pending",
"expires_at": "2026-01-20T09:56:01.045425406Z",
"created_at": "2026-01-20T09:26:01.045403632Z",
"updated_at": "2026-01-20T09:26:01.045403632Z"
}
}
```
Use the quote ID to finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_6T9lPmqMSPPt"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_qaZ4QmI5ahSw",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_6T9lPmqMSPPt",
"description": "Sold USD",
"sub_description": "For NGN",
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "50",
"target_amount": "80363.5",
"trade": "sell",
"rate": {
"product": "USDNGN",
"rate": "1607.27",
"side": "sell",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-20T09:33:40.957016939Z",
"updated_at": "2026-01-20T09:33:40.957017017Z"
}
}
```
Monitor the transfer to confirm completion:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_qaZ4QmI5ahSw \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_qaZ4QmI5ahSw",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_6T9lPmqMSPPt",
"description": "Sold USD",
"sub_description": "For NGN",
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "50",
"target_amount": "80363.5",
"trade": "sell",
"rate": {
"product": "USDNGN",
"rate": "1607.27",
"side": "sell",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your NGN has been added to your wallet."
}
]
},
"created_at": "2026-01-20T09:33:40.957016Z",
"updated_at": "2026-01-20T09:33:42.123456Z"
}
}
```
***
### Sell USD for Crypto
### Convert 50 USD to USDT
Create a quote to see the exchange rate:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USD",
"target_currency": "USDT",
"source_amount": "50",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_g0k6EIlv4ZH6",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USD",
"target_currency": "USDT",
"source_amount": "50",
"target_amount": "49.800796",
"rate": {
"product": "USDTUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_g0k6EIlv4ZH6",
"status": "pending",
"expires_at": "2026-01-20T10:00:31.485131911Z",
"created_at": "2026-01-20T09:30:31.485109051Z",
"updated_at": "2026-01-20T09:30:31.485109051Z"
}
}
```
Use the quote ID to finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_g0k6EIlv4ZH6"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_4vpxeM3IzcuV",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_g0k6EIlv4ZH6",
"description": "Bought USDT",
"sub_description": "With USD",
"source_currency": "USD",
"target_currency": "USDT",
"source_amount": "50",
"target_amount": "49.800796",
"trade": "buy",
"rate": {
"product": "USDTUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-20T09:34:13.772974486Z",
"updated_at": "2026-01-20T09:34:13.772974539Z"
}
}
```
Monitor the transfer to confirm completion:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_4vpxeM3IzcuV \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_4vpxeM3IzcuV",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_g0k6EIlv4ZH6",
"description": "Bought USDT",
"sub_description": "With USD",
"source_currency": "USD",
"target_currency": "USDT",
"source_amount": "50",
"target_amount": "49.800796",
"trade": "buy",
"rate": {
"product": "USDTUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your USDT has been added to your wallet."
}
]
},
"created_at": "2026-01-20T09:34:13.772974Z",
"updated_at": "2026-01-20T09:34:15.456789Z"
}
}
```
### Convert 50 USD to USDC
Create a quote to see the exchange rate:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USD",
"target_currency": "USDC",
"source_amount": "50",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_HAouYZS608yv",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USD",
"target_currency": "USDC",
"source_amount": "50",
"target_amount": "49.800796",
"rate": {
"product": "USDCUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDC"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_HAouYZS608yv",
"status": "pending",
"expires_at": "2026-01-20T10:00:55.785832316Z",
"created_at": "2026-01-20T09:30:55.785806405Z",
"updated_at": "2026-01-20T09:30:55.785806405Z"
}
}
```
Use the quote ID to finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_HAouYZS608yv"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_5ALpSQdyQlpO",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_HAouYZS608yv",
"description": "Bought USDC",
"sub_description": "With USD",
"source_currency": "USD",
"target_currency": "USDC",
"source_amount": "50",
"target_amount": "49.800796",
"trade": "buy",
"rate": {
"product": "USDCUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDC"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-20T09:34:50.233122674Z",
"updated_at": "2026-01-20T09:34:50.233122727Z"
}
}
```
Monitor the transfer to confirm completion:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_5ALpSQdyQlpO \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_5ALpSQdyQlpO",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_HAouYZS608yv",
"description": "Bought USDC",
"sub_description": "With USD",
"source_currency": "USD",
"target_currency": "USDC",
"source_amount": "50",
"target_amount": "49.800796",
"trade": "buy",
"rate": {
"product": "USDCUSD",
"rate": "1.004",
"side": "buy",
"type": "FIXED",
"source_currency": "USD",
"target_currency": "USDC"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your USDC has been added to your wallet."
}
]
},
"created_at": "2026-01-20T09:34:50.233122Z",
"updated_at": "2026-01-20T09:34:51.789456Z"
}
}
```
***
## Learn More
* [Understanding Quotes](/overview/quotes) - Deep dive into how quotes work
* [Create Your First Quote](/guides/quotes/create-first-quote) - Step-by-step guide
* [Supported Currencies](/guides/reference/supported-currencies) - See all available currency pairs
* [Transfer Status Reference](/guides/reference/transfer-status) - All possible transfer statuses
# Sell Crypto for Fiat
Source: https://docs.busha.io/examples/crypto-to-fiat
Sell cryptocurrency for fiat currency using Busha's API.
This example shows you how to sell cryptocurrency (USDT, BTC, ETH, etc.) for fiat currency (NGN, KES) using Busha's API.
## Use Cases
* Cash out crypto to local bank account
* Pay vendors in local currency from crypto balance
* Sell stablecoins for local currency to cover expenses
## Example: Sell Crypto for Fiat
### Sell 100 USDT for NGN
Create a quote to see the exchange rate and how much fiat you'll receive:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"pay_in": {
"type": "address",
"network": "TRX"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_KfCZEaXJD10W",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "147386",
"rate": {
"product": "USDTNGN",
"rate": "1473.86",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"network": "TRX",
"type": "address"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_KfCZEaXJD10W",
"status": "pending",
"expires_at": "2026-01-23T11:35:48.561357552Z",
"created_at": "2026-01-23T11:05:48.561332107Z",
"updated_at": "2026-01-23T11:05:48.561332107Z"
}
}
```
Use the quote ID to get the crypto deposit address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_KfCZEaXJD10W"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_6qPeJdrePrj6",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_KfCZEaXJD10W",
"description": "Sold USDT",
"sub_description": "For NGN",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "147386",
"trade": "sell",
"rate": {
"product": "USDTNGN",
"rate": "1473.86",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"address": "TDbX2dG8s9fLNg4YBGPsoAHFzzYgY5df57",
"expires_at": "2026-01-23T12:08:54.983548Z",
"network": "TRX",
"type": "address"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-23T11:08:54.912314446Z",
"updated_at": "2026-01-23T11:08:54.912314516Z"
}
}
```
**Important:** Send exactly 100 USDT (TRC20) to the address `TDbX2dG8s9fLNg4YBGPsoAHFzzYgY5df57` before the expiration time. The NGN will be credited to your balance once the deposit is confirmed on-chain.
Monitor the transfer to confirm the sale completed successfully:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_6qPeJdrePrj6 \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_6qPeJdrePrj6",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_KfCZEaXJD10W",
"description": "Sold USDT",
"sub_description": "For NGN",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "147386",
"trade": "sell",
"rate": {
"product": "USDTNGN",
"rate": "1473.86",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"address": "TDbX2dG8s9fLNg4YBGPsoAHFzzYgY5df57",
"expires_at": "2026-01-23T12:08:54.983548Z",
"network": "TRX",
"type": "address"
},
"status": "pending",
"timeline": {
"total_steps": 3,
"current_step": 1,
"transfer_status": "pending",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your USDT deposit",
"timestamp": "2026-01-23T11:08:54.9123Z"
},
{
"step": 2,
"done": false,
"status": "funds_received",
"title": "Crypto Received",
"description": "We received your USDT Deposit",
"timestamp": "2026-01-23T11:08:54.9123Z"
},
{
"step": 3,
"done": false,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Money has been added to your wallet.",
"timestamp": "2026-01-23T11:08:54.912309Z"
}
]
},
"created_at": "2026-01-23T11:08:54.912314Z",
"updated_at": "2026-01-23T11:08:54.912314Z"
}
}
```
### Sell 10 USDT for KES
Create a quote to see the exchange rate and how much fiat you'll receive:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_VmvpRemZACRy",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"target_amount": "1305",
"rate": {
"product": "USDTKES",
"rate": "130.5",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "KES"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_VmvpRemZACRy",
"status": "pending",
"expires_at": "2025-11-20T15:37:26.674151054Z",
"created_at": "2025-11-20T15:07:26.67398174Z"
}
}
```
Use the quote ID to finalize the sale:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_VmvpRemZACRy"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_5d7yGiWuNUZP",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_VmvpRemZACRy",
"description": "Sold USDT",
"sub_description": "For KES",
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"target_amount": "1305",
"trade": "sell",
"rate": {
"product": "USDTKES",
"rate": "130.5",
"side": "sell",
"type": "FIXED"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-11-20T15:11:04.27887877Z",
"updated_at": "2025-11-20T15:11:04.27887877Z"
}
}
```
Monitor the transfer to confirm the sale completed successfully:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_5d7yGiWuNUZP \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_5d7yGiWuNUZP",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_VmvpRemZACRy",
"description": "Sold USDT",
"sub_description": "For KES",
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"target_amount": "1305",
"trade": "sell",
"rate": {
"product": "USDTKES",
"rate": "130.5",
"side": "sell",
"type": "FIXED"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Crypto Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Money has been added to your wallet."
}
]
},
"created_at": "2025-11-20T15:11:04.27887Z",
"updated_at": "2025-11-20T15:11:05.456789Z"
}
}
```
***
## Other Currency Combinations
**Sell BTC for NGN**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.001",
"pay_in": {
"type": "balance"
}
}'
```
**Sell ETH for KES**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "ETH",
"target_currency": "KES",
"source_amount": "0.01",
"pay_in": {
"type": "address",
"network": "ETH"
}
}'
```
***
## Learn More
* [Understanding Quotes](/overview/quotes) - Deep dive into how quotes work
* [Process Payouts](/guides/payouts/process-payouts) - Step-by-step payout guide
* [Supported Currencies](/guides/reference/supported-currencies) - See all available currency pairs
* [Transfer Status Reference](/guides/reference/transfer-status) - All possible transfer statuses
# Customer Deposits
Source: https://docs.busha.io/examples/customer-deposits
Accept fiat and crypto deposits using temporary bank accounts and addresses.
This example shows you how to accept deposits into your Busha account via fiat (temporary bank accounts) or crypto (deposit addresses).
## Use Cases
* Customer funding their wallet
* Accepting payments from users
* Processing incoming transfers
* Topping up account balances
## Fiat Deposit via Temporary Bank Account
Create a quote to generate a temporary bank account:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "50000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_vxcF2svmjMbxDp4T5dcD8",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "50000",
"target_amount": "49500",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "500",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"type": "temporary_bank_account"
},
"status": "pending",
"expires_at": "2025-02-21T10:46:56.232278869Z",
"created_at": "2025-02-21T10:16:54.40130914Z",
"updated_at": "2025-02-21T10:16:54.401309215Z"
}
}
```
Use the quote ID to generate the temporary bank account:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_LJB2GQb55Cs98LbpqgRMx",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "50000",
"target_amount": "49500",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "500",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2025-02-21T10:46:56.232278869Z",
"recipient_details": {
"account_name": "Payaza(Business 1 Business)",
"account_number": "7000384620",
"bank_name": "78 FINANCE COMPANY LIMITED",
"email": "support@busha.co"
},
"type": "temporary_bank_account"
},
"status": "pending",
"created_at": "2025-02-21T10:16:54.40130914Z",
"updated_at": "2025-02-21T10:16:54.401309215Z"
}
}
```
Show the temporary bank account details to your customer:
**Account Details:**
* Bank Name: 78 FINANCE COMPANY LIMITED
* Account Number: 7000384620
* Account Name: Payaza(Business 1 Business)
* Amount to Send: 50,000 NGN
* Expires: 2025-02-21 at 10:46 AM
Customer transfers money to this account from their bank app.
Check the transfer status to confirm when funds are received:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_LJB2GQb55Cs98LbpqgRMx \
-H "Authorization: Bearer YOUR_SECRET_TOKEN"
```
**Possible Statuses:**
* `pending` - Awaiting customer's bank transfer
* `processing` - Funds received, being processed
* `funds_received` - Successfully credited to your balance
* `cancelled` - Transfer cancelled
***
## Crypto Deposit via Address
Create a quote to generate a crypto deposit address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "100",
"pay_in": {
"type": "address",
"network": "TRX"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_GxYibGxTIN5c",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "100",
"target_amount": "100",
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"network": "TRX",
"type": "address"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_GxYibGxTIN5c",
"status": "pending",
"created_at": "2025-10-30T14:35:16.487382045Z",
"updated_at": "2025-10-30T14:35:16.487382045Z"
}
}
```
Use the quote ID to generate the crypto deposit address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_GxYibGxTIN5c"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_abc123xyz",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"quote_id": "QUO_GxYibGxTIN5c",
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "100",
"target_amount": "100",
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"type": "address",
"address": "TXYZabc123def456ghi789jkl",
"network": "TRX",
"memo": null
},
"status": "pending",
"created_at": "2025-10-30T14:35:20.123456Z",
"updated_at": "2025-10-30T14:35:20.123456Z"
}
}
```
Show the crypto deposit details to your customer:
**Deposit Instructions:**
* Network: TRX (Tron)
* Address: TXYZabc123def456ghi789jkl
* Asset: USDT
* Amount: 100 USDT (minimum)
Customer sends USDT to this address from their wallet.
Check the transfer status to confirm when crypto is received:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_abc123xyz \
-H "Authorization: Bearer YOUR_SECRET_TOKEN"
```
**Possible Statuses:**
* `pending` - Awaiting blockchain confirmation
* `processing` - Transaction confirmed, processing deposit
* `funds_received` - Crypto credited to balance
* `cancelled` - Deposit cancelled
***
## Deposit for a Customer
To process deposits on behalf of a customer, include the customer's profile ID in the header:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "X-BU-PROFILE-ID: CUSTOMER_PROFILE_ID" \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "50000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
The deposit will be credited to the customer's account instead of your business account.
***
## Supported Networks for Crypto Deposits
* **USDT**: TRX (Tron), ERC20 (Ethereum), BEP20 (BSC), POLYGON
* **BTC**: BTC (Bitcoin)
* **ETH**: ETH (Ethereum)
* **Other cryptos**: Check supported networks via the Pairs API
***
## Important Notes
### Fiat Deposits
* Temporary bank accounts expire after 30 minutes
* Always check the `expires_at` field
* If expired, create a new quote and transfer
* Fees are deducted from the deposited amount
### Crypto Deposits
* Always specify the correct network
* Deposits require blockchain confirmations
* Minimum deposit amounts apply per asset
* Wrong network = lost funds (unrecoverable)
***
## Learn More
* [Process Fiat Deposits Guide](/guides/deposits/process-fiat-deposits) - Detailed fiat deposit guide
* [Process Crypto Deposits Guide](/guides/deposits/process-crypto-deposits) - Detailed crypto deposit guide
* [Understanding Quotes](/overview/quotes) - How quotes work
* [Webhooks Setup](/guides/webhooks/setup) - Monitor deposits in real-time
* [Initiate Transactions on Behalf of Customers](/guides/customers/transactions-on-behalf) - Customer transactions
# Customer Payouts
Source: https://docs.busha.io/examples/customer-payouts
Process crypto-to-fiat payouts to bank accounts and mobile money.
This example shows you how to process payouts from crypto to fiat bank accounts or mobile money wallets.
## Use Cases
* Vendor payments from marketplace
* Salary disbursements in local currency
* Cash out crypto to bank account
* Mobile money withdrawals
## Crypto to Fiat Payout
### Bank Transfer Payout
First, create a recipient for the Nigerian bank account:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/recipients \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "X-BU-VERSION: 2025-07-11" \
-H "Content-Type: application/json" \
-d '{
"currency": "NGN",
"country_code": "NG",
"type": "ngn_bank",
"bank_name": "UNITED BANK FOR AFRICA",
"bank_code": "033",
"account_number": "2109328188",
"account_name": "SOSANYA DICKSON OLUMIDE"
}'
```
Save the `recipient_id` from the response.
Create a quote specifying how much crypto to convert and send:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"pay_out": {
"type": "bank_transfer",
"recipient_id": "677bbf9c7cf061f23784555a"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_mprvCPMCfm3K2qSnzbWj7",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "168876",
"rate": {
"product": "USDTNGN",
"rate": "1690.76",
"side": "sell",
"type": "FIXED"
},
"fees": [
{
"amount": {
"amount": "200",
"currency": "NGN"
},
"name": "Fees",
"type": "FIXED"
}
],
"pay_out": {
"recipient_details": {
"account_name": "SOSANYA DICKSON OLUMIDE",
"account_number": "2109328188",
"bank_name": "UNITED BANK FOR AFRICA",
"country": "NG"
},
"recipient_id": "677bbf9c7cf061f23784555a",
"type": "bank_transfer"
},
"expires_at": "2025-02-20T10:58:19.540052923Z"
}
}
```
Finalize the payout using the quote ID:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_mprvCPMCfm3K2qSnzbWj7"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_tYZ1y5bmXv4N5IhXSMbWJ",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "168876",
"pay_out": {
"recipient_details": {
"account_name": "SOSANYA DICKSON OLUMIDE",
"account_number": "2109328188",
"bank_name": "UNITED BANK FOR AFRICA",
"country": "NG"
},
"type": "bank_transfer"
},
"status": "pending"
}
}
```
Check the transfer status to confirm delivery:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_tYZ1y5bmXv4N5IhXSMbWJ \
-H "Authorization: Bearer YOUR_SECRET_TOKEN"
```
**Possible Statuses:**
* `pending` - Payout initiated
* `processing` - Funds being processed
* `funds_delivered` - Successfully delivered to bank account
* `cancelled` - Payout cancelled
### M-Pesa Mobile Money Payout
First, create a recipient for the M-Pesa mobile money wallet:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/recipients \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "X-BU-VERSION: 2025-07-11" \
-H "Content-Type: application/json" \
-d '{
"type": "mpesa_mobile_money",
"account_name": "Samuel Kiprotich",
"phone_number": "254712345678"
}'
```
Save the `recipient_id` from the response.
Create a quote specifying how much crypto to convert and send:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"pay_out": {
"type": "mobile_money",
"recipient_id": "6923ca7f32faa00bb0932c78"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_F5I5r0Mhnrpa",
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"target_amount": "1236.3",
"rate": {
"product": "USDTKES",
"rate": "129.63",
"side": "sell",
"type": "FIXED"
},
"fees": [
{
"amount": {
"amount": "60",
"currency": "KES"
},
"name": "Fees",
"type": "TIERED"
}
],
"pay_out": {
"recipient_details": {
"account_name": "Samuel Kiprotich",
"country_code": "KE",
"currency": "KES",
"phone_number": "254712345678"
},
"recipient_id": "6923ca7f32faa00bb0932c78",
"type": "mobile_money"
},
"expires_at": "2025-11-24T03:32:06.233668598Z"
}
}
```
Finalize the payout using the quote ID:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_F5I5r0Mhnrpa"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_GbqoYfHekk9f",
"source_currency": "USDT",
"target_currency": "KES",
"source_amount": "10",
"target_amount": "1236.3",
"pay_out": {
"recipient_details": {
"account_name": "Samuel Kiprotich",
"country_code": "KE",
"currency": "KES",
"phone_number": "254712345678"
},
"type": "mobile_money"
},
"status": "pending"
}
}
```
Check the transfer status to confirm delivery:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_GbqoYfHekk9f \
-H "Authorization: Bearer YOUR_SECRET_TOKEN"
```
**Possible Statuses:**
* `pending` - Payout initiated
* `processing` - Funds being processed
* `funds_delivered` - Successfully delivered to M-Pesa wallet
* `cancelled` - Payout cancelled
***
## Payout for a Customer
To process payouts on behalf of a customer, include the customer's profile ID:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "X-BU-PROFILE-ID: CUSTOMER_PROFILE_ID" \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"pay_out": {
"type": "bank_transfer",
"recipient_id": "677bbf9c7cf061f23784555a"
}
}'
```
The payout will be processed from the customer's balance.
***
## Payout Methods by Country
Country
Currency
Method
Recipient Type
Nigeria
NGN
Bank transfer
ngn\_bank
Kenya
KES
M-Pesa mobile money
mpesa\_mobile\_money
***
## Important Notes
* Recipients must be created before payouts
* Quotes expire after 30 minutes
* Fees are deducted from the payout amount
* Use webhooks for real-time status updates
* Bank transfers typically complete within minutes
* Mobile money transfers are usually instant
***
## Learn More
* [Process Payouts Guide](/guides/payouts/process-payouts) - Detailed payout guide
* [Create Recipients](/guides/recipients/create-and-manage) - Recipient management
* [Understanding Quotes](/overview/quotes) - How quotes work
* [Webhooks Setup](/guides/webhooks/setup) - Monitor payouts in real-time
* [Initiate Transactions on Behalf of Customers](/guides/customers/transactions-on-behalf) - Customer transactions
# Buy Crypto with Fiat
Source: https://docs.busha.io/examples/fiat-to-crypto
Buy cryptocurrency with fiat currency using Busha's API.
This example shows you how to buy cryptocurrency (USDT, BTC, etc.) with fiat currency (NGN, KES) using Busha's API.
## Use Cases
* Buy Bitcoin with local currency
* Buy stablecoins for international payments
* Purchase crypto from local currency balance
## Example: Buy Crypto with Fiat
### Buy USDT with 50,000 NGN via Bank Transfer
Create a quote with temporary bank account funding:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_gCcLjJ0P0uEc",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"target_amount": "33.48543819",
"rate": {
"product": "USDTNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USDT"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"type": "temporary_bank_account"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_gCcLjJ0P0uEc",
"status": "pending",
"expires_at": "2026-01-23T11:34:17.175170741Z",
"created_at": "2026-01-23T11:04:17.175146315Z",
"updated_at": "2026-01-23T11:04:17.175146315Z"
}
}
```
Use the quote ID to get temporary bank details:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_gCcLjJ0P0uEc"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_JSaOYnl7Sla0",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_gCcLjJ0P0uEc",
"description": "Bought USDT",
"sub_description": "With NGN",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"target_amount": "33.48543819",
"trade": "buy",
"rate": {
"product": "USDTNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USDT"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2026-01-23T11:37:32.289498887Z",
"recipient_details": {
"account_name": "BIBAGE TECHNOLOGIES LTD || Liverppol Business",
"account_number": "0327318166",
"bank_code": "090614",
"bank_name": "Aella Microfinance Bank",
"email": "ajibola@busha.co"
},
"type": "temporary_bank_account"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-01-23T11:07:31.197428968Z",
"updated_at": "2026-01-23T11:07:31.197429043Z"
}
}
```
**Important:** Transfer exactly ₦50,000 to the provided bank account before the expiration time. The USDT will be credited to your balance once payment is confirmed.
Monitor the transfer to confirm the purchase completed successfully:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_JSaOYnl7Sla0 \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_JSaOYnl7Sla0",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_gCcLjJ0P0uEc",
"description": "Bought USDT",
"sub_description": "With NGN",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"target_amount": "33.48543819",
"trade": "buy",
"rate": {
"product": "USDTNGN",
"rate": "1490.2",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USDT"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2026-01-23T11:37:32.289498887Z",
"recipient_details": {
"account_name": "BIBAGE TECHNOLOGIES LTD || Liverppol Business",
"account_number": "0327318166",
"bank_code": "090614",
"bank_name": "Aella Microfinance Bank",
"email": "ajibola@busha.co"
},
"type": "temporary_bank_account"
},
"status": "funds_converted",
"timeline": {
"total_steps": 3,
"current_step": 3,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your NGN payment",
"timestamp": "2026-01-23T11:07:34.553579Z"
},
{
"step": 2,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "We received your NGN Payment",
"timestamp": "2026-01-23T11:07:34.553579Z"
},
{
"step": 3,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your USDT has been added to your wallet.",
"timestamp": "2026-01-23T11:07:34.65765Z"
}
]
},
"created_at": "2026-01-23T11:07:31.197428Z",
"updated_at": "2026-01-23T11:07:35.404245Z"
}
}
```
### Buy BTC with 1,000 KES
First, create a quote to see the exchange rate and how much crypto you'll receive:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "1000",
"pay_in": {
"type": "balance"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_a5D3oflYiz78",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "1000",
"target_amount": "0.00008471",
"rate": {
"product": "BTCKES",
"rate": "11803984.7",
"side": "buy",
"type": "FIXED",
"source_currency": "KES",
"target_currency": "BTC"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"reference": "QUO_a5D3oflYiz78",
"status": "pending",
"expires_at": "2025-11-20T16:00:35.039961155Z",
"created_at": "2025-11-20T15:30:35.039935771Z"
}
}
```
Use the quote ID to finalize the purchase:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_a5D3oflYiz78"
}'
```
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_vvTf73YOwNFD",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_a5D3oflYiz78",
"description": "Bought BTC",
"sub_description": "With KES",
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "1000",
"target_amount": "0.00008471",
"trade": "buy",
"rate": {
"product": "BTCKES",
"rate": "11803984.7",
"side": "buy",
"type": "FIXED"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-11-20T15:33:06.12036014Z",
"updated_at": "2025-11-20T15:33:06.12036014Z"
}
}
```
Monitor the transfer to confirm the purchase completed successfully:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/transfers/TRF_vvTf73YOwNFD \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
```json theme={null}
{
"status": "success",
"message": "Fetched transfer successfully",
"data": {
"id": "TRF_vvTf73YOwNFD",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_a5D3oflYiz78",
"description": "Bought BTC",
"sub_description": "With KES",
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "1000",
"target_amount": "0.00008471",
"trade": "buy",
"rate": {
"product": "BTCKES",
"rate": "11803984.7",
"side": "buy",
"type": "FIXED"
},
"fees": [],
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "balance"
},
"status": "funds_converted",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Payment Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Your BTC has been added to your wallet."
}
]
},
"created_at": "2025-11-20T15:33:06.12036Z",
"updated_at": "2025-11-20T15:33:07.456789Z"
}
}
```
***
## Other Currency Combinations
**Buy ETH with NGN**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "ETH",
"source_amount": "100000",
"pay_in": {
"type": "balance"
}
}'
```
**Buy ETH with KES**
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "KES",
"target_currency": "ETH",
"source_amount": "5000",
"pay_in": {
"type": "balance"
}
}'
```
***
## Learn More
* [Understanding Quotes](/overview/quotes) - Deep dive into how quotes work
* [Create Your First Quote](/guides/quotes/create-first-quote) - Step-by-step guide
* [Supported Currencies](/guides/reference/supported-currencies) - See all available currency pairs
* [Transfer Status Reference](/guides/reference/transfer-status) - All possible transfer statuses
# Introduction to Examples
Source: https://docs.busha.io/examples/introduction
Explore practical code examples and integration patterns for common Busha use cases.
Welcome to the Busha Examples section. Here you'll find **production-ready code snippets** for the most common integration patterns. Each example is designed to be copied and adapted to your use case.
**What You'll Achieve:**
* Get working code examples you can copy and use immediately in your application
* See complete end-to-end implementations with real API requests and responses
* Learn best practices through practical, production-ready patterns
* Quickly integrate Busha features without reading through lengthy documentation
## Prerequisites
Before using these examples, ensure you have:
* A Busha Business Account ([Sign up here](https://dash.busha.io/business/signup))
* [API Keys (Secret and Public) from your dashboard](/guides/getting-started/generate-api-key)
## How to Use These Examples
1. **Copy the code** - Each example is complete and ready to use
2. **Replace credentials** - Update `YOUR_SECRET_KEY`, `YOUR_BASE_URL`, etc. with your actual values
3. **Test in sandbox** - Always test in the sandbox environment first
4. **Adapt to your needs** - Modify parameters to fit your specific use case
5. **Read the guides** - Each example links to detailed guides for deeper understanding
## Quick Links
Convert NGN/KES to USDT, BTC, and other cryptocurrencies
Cash out crypto to bank accounts or mobile money
Process crypto-to-fiat payouts to bank accounts and mobile money
Create shareable payment links for invoices and products
## Need More Help?
* **Detailed Guides:** Check our [Guides section](/guides) for step-by-step tutorials
* **API Reference:** See the [API Reference](/api-reference) for complete endpoint documentation
* **Support:** Contact us at [developers@busha.co](mailto:developers@busha.co)
All examples use sandbox URLs and test data. Remember to switch to production
URLs and real API keys when going live.
# Payment Links
Source: https://docs.busha.io/examples/payment-links
Create payment links to accept crypto payments from customers.
This example shows you how to create and manage payment links for accepting crypto payments.
## Use Cases
* E-commerce product checkout
* Invoice payments
* Donation campaigns
* Subscription billing
* Service payments
## Reusable Payment Links
Reusable payment links can be used multiple times by different customers. They're ideal for ongoing sales, subscriptions, or recurring donations.
### Create a Fixed Amount Reusable Link
Create a payment link for a specific amount that can be used multiple times:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/payments/links \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"fixed": true,
"one_time": false,
"name": "Product Payment Example",
"title": "Buy Premium Package",
"description": "Payment for premium subscription",
"quote_amount": "10000",
"quote_currency": "NGN",
"target_currency": "USDT",
"require_extra_info": [
{
"field_name": "email",
"required": true
}
],
"dry_run": false
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Payment link created successfully",
"data": {
"id": "YgFdIGWCWY3G",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"fixed": true,
"one_time": false,
"name": "Product Payment Example",
"title": "Buy Premium Package",
"description": "Payment for premium subscription",
"quote_amount": "10000",
"quote_currency": "NGN",
"target_currency": "USDT",
"meta": {
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
},
"status": "active",
"created_at": "2025-10-30T11:29:42.842496434Z",
"updated_at": "2025-10-30T11:29:42.842496434Z",
"link": "YgFdIGWCWY3G"
}
}
```
### Create a Variable Amount Reusable Link
Create a payment link where customers choose their own amount:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/payments/links \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"fixed": false,
"one_time": false,
"name": "Donation Link",
"title": "Support Our Project",
"description": "Donate any amount you wish",
"quote_currency": "NGN",
"target_currency": "USDT",
"require_extra_info": [
{
"field_name": "email",
"required": true
}
],
"dry_run": false
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Payment link created successfully",
"data": {
"id": "AAuHvoU6NkKs",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"fixed": false,
"one_time": false,
"name": "Donation Link",
"title": "Support Our Project",
"description": "Donate any amount you wish",
"quote_currency": "NGN",
"target_currency": "USDT",
"meta": {
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
},
"status": "active",
"created_at": "2025-10-30T11:30:29.223574773Z",
"updated_at": "2025-10-30T11:30:29.223574773Z",
"link": "AAuHvoU6NkKs"
}
}
```
## One-Time Payment Links
One-time payment links are designed for single-use scenarios like invoices or unique transactions. Once paid, the link becomes inactive.
### Create a One-Time Fixed Amount Link
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/payments/links \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"fixed": true,
"one_time": true,
"name": "Invoice #12345",
"title": "Pay Invoice",
"description": "One-time invoice payment",
"quote_amount": "50000",
"quote_currency": "NGN",
"target_currency": "USDT",
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Payment link created successfully",
"data": {
"id": "XyZ123AbC",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"fixed": true,
"one_time": true,
"name": "Invoice #12345",
"title": "Pay Invoice",
"description": "One-time invoice payment",
"quote_amount": "50000",
"quote_currency": "NGN",
"target_currency": "USDT",
"meta": {
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
},
"status": "active",
"created_at": "2025-10-30T11:35:42.842496434Z",
"updated_at": "2025-10-30T11:35:42.842496434Z",
"link": "XyZ123AbC"
}
}
```
## Retrieve a Payment Link
Get details of an existing payment link:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/payments/links/YgFdIGWCWY3G \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Payment link retrieved successfully",
"data": {
"id": "YgFdIGWCWY3G",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"fixed": true,
"one_time": false,
"name": "Product Payment Example",
"title": "Buy Premium Package",
"description": "Payment for premium subscription",
"quote_amount": "10000",
"quote_currency": "NGN",
"target_currency": "USDT",
"meta": {
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
},
"status": "active",
"created_at": "2025-10-30T11:29:42.842496Z",
"updated_at": "2025-10-30T11:29:42.842496Z",
"link": "YgFdIGWCWY3G",
"pub_key": "pub_iSQAgqGFoVZOaVjYM8ZeW"
}
}
```
## Update a Payment Link
Modify an existing payment link:
```bash theme={null}
curl -X PATCH https://api.sandbox.busha.so/v1/payments/links/YgFdIGWCWY3G \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Product Payment",
"description": "Updated: Premium subscription - now 15,000 NGN",
"quote_amount": "15000"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Payment link updated successfully",
"data": {
"id": "YgFdIGWCWY3G",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"fixed": true,
"one_time": false,
"name": "Updated Product Payment",
"title": "Buy Premium Package",
"description": "Updated: Premium subscription - now 15,000 NGN",
"quote_amount": "15000",
"quote_currency": "NGN",
"target_currency": "USDT",
"meta": {
"require_extra_info": [
{
"field_name": "email",
"required": true
}
]
},
"status": "active",
"created_at": "2025-10-30T11:29:42.842496Z",
"updated_at": "2025-10-30T11:33:05.58691Z",
"link": "YgFdIGWCWY3G"
}
}
```
## Learn More
* [Payment Requests Guide](/guides/payment-requests/create-first-payment) - Create payment requests from links
* [Accepting Stablecoins Guide](/guides/accepting-stablecoin-payments/payment-links) - How to accept USDT and other stablecoins with payment links
* [Accepting Stablecoin Payments with the Widget](/guides/accepting-stablecoin-payments/payment-widget) - How to add stablecoin checkout to your website or app
* [Webhooks Setup](/guides/webhooks/setup) - Monitor payment link transactions
* [API Reference](/api-reference) - Complete payment links API documentation
# Processing Markups
Source: https://docs.busha.io/examples/processing-markups
Add custom markup fees to transactions and generate revenue.
This example shows you how to add custom markup fees on top of Busha's infrastructure costs.
## Use Cases
* Charging service fees on transactions
* Adding profit margins to conversions
## How Markups Work
To add your own fees, use a two-step approach:
1. **Customer Deposit**: Create a quote for the total amount (base + markup) with a `pay_in` object
2. **Actual Conversion**: After funds are received, create a second quote for only the base amount with a `pay_out` object
The difference between what the customer pays and what you spend on the conversion remains in your balance as profit.
***
## Example: Markup on USDT Purchase
A customer wants to buy USDT worth 5,000 NGN. You want to charge a 10% markup (500 NGN profit).
Charge the customer 5,500 NGN (5,000 NGN + 500 NGN markup):
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "5500",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_depositWith5500",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "5500",
"target_amount": "5500",
"pay_in": {
"type": "temporary_bank_account"
},
"status": "pending"
}
}
```
Generate the temporary bank account for customer deposit:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_depositWith5500"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_customerDeposit",
"quote_id": "QUO_depositWith5500",
"source_amount": "5500",
"pay_in": {
"recipient_details": {
"account_name": "Payaza(Business 1 Business)",
"account_number": "7000384620",
"bank_name": "78 FINANCE COMPANY LIMITED"
},
"type": "temporary_bank_account"
},
"status": "pending"
}
}
```
Customer deposits 5,500 NGN to this bank account.
If webhooks is setup, you'll receive a notification when the deposit is complete. The customer's funds are now in your balance and ready for conversion.
```json theme={null}
{
"event": "transfer.funds_received",
"data": {
"transfer_id": "TRF_customerDeposit",
"source_amount": "5500",
"source_currency": "NGN",
"status": "funds_received"
}
}
```
Your balance now has 5,500 NGN.
Convert only 5,000 NGN to USDT (keeping 500 NGN as profit):
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "5000",
"pay_out": {
"type": "balance"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_actualConversion",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "5000",
"target_amount": "3.12",
"rate": {
"rate": "1602.56",
"side": "buy",
"source_currency": "NGN",
"target_currency": "USDT"
},
"pay_out": {
"type": "balance"
}
}
}
```
Finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_actualConversion"
}'
```
**Result:**
* Customer receives 3.12 USDT
* You spent 5,000 NGN from your balance
* 500 NGN remains in your balance as profit
***
## Example: Sell USDT for NGN with Markup
A customer wants to sell 50 USDT for NGN. You want to charge a 5% markup.
Create a quote to see how much NGN the customer will receive:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "50"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_8xTKmNpR2vWq",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "50",
"target_amount": "74487",
"rate": {
"product": "USDTNGN",
"rate": "1489.74",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [],
"reference": "QUO_8xTKmNpR2vWq",
"status": "pending",
"expires_at": "2025-11-27T14:43:26.906019648Z",
"created_at": "2025-11-27T14:13:26.905993939Z"
}
}
```
**Calculate your markup:**
* Base amount: ₦74,487
* 5% markup: ₦3,724
* Customer receives: ₦70,763 (₦74,487 - ₦3,724)
* You keep: ₦3,724 as profit
Use the quote ID to finalize the conversion:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_8xTKmNpR2vWq"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_2mKpVxNzQwYr",
"profile_id": "BUS_9rDAqqREdmMQcQj3zsRlL",
"quote_id": "QUO_8xTKmNpR2vWq",
"description": "Sold USDT",
"sub_description": "For NGN",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "50",
"target_amount": "74487",
"trade": "sell",
"rate": {
"product": "USDTNGN",
"rate": "1489.74",
"side": "sell",
"type": "FIXED"
},
"fees": [],
"status": "pending",
"created_at": "2025-11-27T14:14:06.134616492Z"
}
}
```
**Your transaction breakdown:**
* 50 USDT converted to ₦74,487 (from Busha)
* Customer paid: ₦70,763 (after your 5% markup)
* Your profit: ₦3,724
You would then send ₦70,763 to the customer via bank transfer or their preferred payout method, keeping ₦3,724 as your service fee.
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"target_amount": "70763",
"pay_out": {
"type": "bank_transfer",
"recipient_id": "63837bdybd3783bd"
}
}'
```
***
## Example: Crypto Payout with Markup
A customer wants to withdraw 100 USDT to their external wallet. You want to charge a 2% markup (withdrawal fee).
**Customer request:** Withdraw 100 USDT
**Your calculation:**
* Gross amount: 100 USDT
* 2% markup: 2 USDT
* Net payout: 98 USDT (amount customer actually receives)
* You keep: 2 USDT as profit
Create a crypto recipient for the customer's external wallet address:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/recipients \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "crypto",
"currency": "USDT",
"network": "TRX",
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"account_name": "Customer Wallet"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6996cd8c772863763d64f3e3",
"type": "crypto",
"currency": "USDT",
"network": "TRX",
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"account_name": "Customer Wallet"
}
}
```
Create a quote for the net amount (98 USDT) that the customer will actually receive:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "98",
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "address",
"recipient_id": "6996cd8c772863763d64f3e3"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_payoutNet98USDT",
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "98",
"target_amount": "98",
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "address",
"recipient_id": "6996cd8c772863763d64f3e3",
"network": "TRX"
},
"status": "pending"
}
}
```
Finalize the payout:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_payoutNet98USDT"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_cryptoPayout",
"quote_id": "QUO_payoutNet98USDT",
"source_amount": "98",
"source_currency": "USDT",
"target_amount": "98",
"target_currency": "USDT",
"pay_out": {
"type": "address",
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"network": "TRX"
},
"status": "pending"
}
}
```
**Result:**
* Customer receives: 98 USDT in their external wallet
* You spent: 98 USDT from your balance
* You keep: 2 USDT as profit (from the original 100 USDT customer paid you)
If webhooks are set up, you'll receive notifications as the payout progresses:
```json theme={null}
{
"event": "transfer.completed",
"data": {
"transfer_id": "TRF_cryptoPayout",
"source_amount": "98",
"source_currency": "USDT",
"status": "completed",
"pay_out": {
"type": "address",
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"network": "TRX"
}
}
}
```
**Transaction Summary:**
* Customer paid you: 100 USDT
* Customer received: 98 USDT
* Your markup profit: 2 USDT
* Network fee: Covered by Busha
***
## Example: Bank Payout with Markup
A customer wants to withdraw 50,000 NGN to their bank account. You charge a 1% markup (500 NGN).
**Customer request:** Withdraw 50,000 NGN
**Your calculation:**
* Gross amount: 50,000 NGN
* 1% markup: 500 NGN
* Net payout: 49,500 NGN
* You keep: 500 NGN as profit
Create a recipient for the customer's bank account:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/recipients \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"currency": "NGN",
"country_code": "NG",
"type": "ngn_bank",
"bank_name": "GUARANTY TRUST BANK",
"bank_code": "000013",
"account_number": "0123456789",
"account_name": "John Doe"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "69980a2c70586e72bb718d1aa",
"type": "ngn_bank",
"currency": "NGN",
"bank_name": "GUARANTY TRUST BANK",
"bank_code": "000013",
"account_number": "0123456789",
"account_name": "John Doe"
}
}
```
Create a quote for 49,500 NGN (after your 1% markup):
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/quotes \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "49500",
"pay_in": {
"type": "balance"
},
"pay_out": {
"type": "bank_transfer",
"recipient_id": "69980a2c70586e72bb718d1aa"
}
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_bankPayout49500",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "49500",
"target_amount": "49500",
"pay_out": {
"type": "bank_transfer",
"recipient_id": "69980a2c70586e72bb718d1aa"
},
"fees": [
{
"name": "Transfer Fee",
"amount": "107.50",
"type": "FIXED",
"currency": "NGN"
}
],
"status": "pending"
}
}
```
Finalize the bank transfer:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "QUO_bankPayout49500"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_bankPayout",
"quote_id": "QUO_bankPayout49500",
"source_amount": "49500",
"target_amount": "49500",
"pay_out": {
"type": "bank_transfer",
"recipient_details": {
"account_name": "John Doe",
"account_number": "0123456789",
"bank_name": "GUARANTY TRUST BANK"
}
},
"status": "pending"
}
}
```
**Result:**
* Customer receives: ₦49,500 in their bank account
* You spent: ₦49,607.50 from your balance (₦49,500 + ₦107.50 transfer fee)
* Your markup profit: ₦500 (before transfer fee)
* Net profit: ₦392.50 (after ₦107.50 transfer fee)
***
## Learn More
* [Customer Deposits](/examples/customer-deposits) - Accept fiat and crypto deposits
* [Sell Crypto for Fiat](/examples/crypto-to-fiat) - Sell cryptocurrency for fiat
* [Webhooks Setup](/guides/webhooks/setup) - Monitor transaction status
* [Understanding Quotes](/overview/quotes) - How quotes work
# Accept Stablecoin with Mobile SDK
Source: https://docs.busha.io/guides/accepting-stablecoin-payments/mobile-sdks
Add Busha crypto checkout to your iOS, Android, or Flutter app using the Busha Pay mobile SDKs.
The Busha Pay mobile SDKs let you embed a crypto checkout experience directly into your mobile app. Users can pay with their Busha wallet or externally without leaving your app. Four SDKs are available; React Native, iOS (Swift), Android (Kotlin), and Flutter.
**What You'll Achieve:**
1. Install the Busha Pay SDK for your platform
2. Initialize the SDK with your public key
3. Launch checkout and handle payment results
4. Configure platform-specific deep link callbacks
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Public API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* A React Native, iOS, Android, or Flutter mobile application.
**Important Note:** The mobile SDKs use your Public API Key, not your Secret
API Key. Your Public API Key is automatically generated for your account — you
do not need to create a new token to access it. You can find it in **Settings
→ Developer Tools → API Tokens**.
## Installation
View the full React Native SDK source, releases, and changelog on GitHub.
**Requirements:** React Native 0.68+, Node.js 18+
Install the SDK and its peer dependencies:
```bash theme={null}
npm install @busha/pay-react-native react-native-webview expo-application
# or
yarn add @busha/pay-react-native react-native-webview expo-application
```
**Installing from GitHub releases**
Each release ships an npm-installable tarball on GitHub under tags shaped `react-native/v`. You can install directly without going through the npm registry:
```bash theme={null}
npm install https://github.com/bushaHQ/pay/releases/download/react-native/v0.0.1/busha_pay_react_native-0.0.1.tgz
# or with yarn:
yarn add https://github.com/bushaHQ/pay/releases/download/react-native/v0.0.1/busha_pay_react_native-0.0.1.tgz
```
Then install the peer dependencies separately:
```bash theme={null}
npm install react-native-webview expo-application
```
**Bare React Native setup**
If your app is bare React Native (not Expo), run this once to enable Expo modules:
```bash theme={null}
npx install-expo-modules@latest
```
Expo managed, Expo dev client, and Expo Go users can skip this step.
View the full iOS SDK source, releases, and Swift Package Manager setup on
GitHub.
**Requirements:** iOS 14+, Swift 5.9+, Xcode 15+
**Installing via Swift Package Manager (recommended)**
In Xcode, go to **File → Add Package Dependencies…** and enter:
[https://github.com/bushaHQ/pay-ios](https://github.com/bushaHQ/pay-ios)
Select your version, choose the `BushaPay` library, and add it to your app target.
For `Package.swift`:
```swift theme={null}
.package(url: "https://github.com/bushaHQ/pay-ios", from: "0.0.1"),
```
Then add `BushaPay` as a dependency to your target:
```swift theme={null}
.target(
name: "YourApp",
dependencies: ["BushaPay"]
)
```
The SDK is authored in the [bushaHQ/pay](https://github.com/bushaHQ/pay)
monorepo under `ios/`. Each release is mirrored to the standalone
[bushaHQ/pay-ios](https://github.com/bushaHQ/pay-ios) repository so Swift
Package Manager can resolve it correctly. Issues, PRs, and source code live in
the monorepo.
View the full Android SDK source, releases, and changelog on GitHub.
**Requirements:** Android 5.0 (API 21)+, Kotlin 1.9+, AndroidX
**Installing via JitPack**
Add the JitPack repository to your `settings.gradle.kts`:
```kotlin theme={null}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
```
Then add the dependency to your module's `build.gradle.kts`:
```kotlin theme={null}
dependencies {
implementation("com.github.bushaHQ.pay-android:pay-android:0.0.1")
}
```
The SDK is authored in the [bushaHQ/pay](https://github.com/bushaHQ/pay)
monorepo under `android/`. Each release is mirrored to the standalone
[bushaHQ/pay-android](https://github.com/bushaHQ/pay-android) repository that
JitPack builds from. Issues, PRs, and source code live in the monorepo. The
SDK ships with a single runtime dependency — `androidx.webkit` — which it uses
to inject the checkout bridge reliably across WebView versions.
View the full Flutter SDK package, documentation, and changelog on pub.dev.
**Requirements:** Flutter 3.0+, Dart 3.0+
**Installing from pub.dev (recommended)**
Add `busha_pay` to your `pubspec.yaml`:
```yaml theme={null}
dependencies:
busha_pay: ^0.0.1
```
Then run:
```bash theme={null}
flutter pub get
```
**Installing from GitHub**
Each release ships as a zipped artifact on GitHub under tags shaped `flutter/v`. To install directly from the monorepo without going through pub.dev:
```yaml theme={null}
dependencies:
busha_pay:
git:
url: https://github.com/bushaHQ/pay
ref: flutter/v0.0.1
path: flutter
```
Replace `v0.0.1` with the version you want. Every git checkout re-resolves from the tagged commit, so your lockfile stays reproducible.
## Initialize the SDK
Initialize once at app startup before any checkout is triggered.
Wrap your root component with `BushaPayProvider`. The provider calls `BushaPay.init()` on mount and auto-detects your app's bundle ID.
```javascript theme={null}
import { BushaPayProvider } from '@busha/pay-react-native'
export default function App() {
return (
)
}
```
Use `environment="live"` for production.
Call `BushaPay.initialize` in your `AppDelegate` or `@main` app before any views load:
```swift theme={null}
import BushaPay
BushaPay.initialize(
publicKey: "pub_xxx",
environment: .sandbox // or .live
)
```
Call `BushaPay.initialize` once from your `Application` class:
```kotlin theme={null}
import android.app.Application
import co.busha.pay.BushaEnvironment
import co.busha.pay.BushaPay
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
BushaPay.initialize(
context = this,
publicKey = "pub_xxx",
environment = BushaEnvironment.SANDBOX, // or BushaEnvironment.LIVE
)
}
}
```
Call `BushaPay.init` in `main()` before `runApp`:
```dart theme={null}
import 'package:busha_pay/busha_pay.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await BushaPay.init(
publicKey: 'pub_xxx',
environment: BushaEnvironment.sandbox, // or .live
);
runApp(const MyApp());
}
```
## Launch Checkout
```javascript theme={null}
import { Button } from 'react-native'
import { useBushaPay } from '@busha/pay-react-native'
function PayButton() {
const { checkout } = useBushaPay()
const onPress = async () => {
const result = await checkout({
quoteAmount: '10000',
quoteCurrency: 'NGN',
targetCurrency: 'NGN',
sourceCurrency: 'USDT',
metaName: 'John Doe',
metaEmail: 'john@example.com',
})
switch (result.type) {
case 'success':
console.log('Payment completed:', result.paymentId)
break
case 'cancelled':
console.log('Cancelled:', result.reason)
break
case 'error':
console.log('Error:', result.message)
break
}
}
return
}
```
```swift theme={null}
import BushaPay
import UIKit
BushaPay.checkout(
config: BushaPayConfig(
quoteAmount: "10000",
quoteCurrency: "NGN",
targetCurrency: "NGN",
sourceCurrency: "USDT",
metaName: "Jane Doe",
metaEmail: "jane@example.com"
),
from: viewController
) { result in
switch result {
case .success(let payment):
print("Paid: \(payment.paymentId)")
case .cancelled(let cancelled):
print("Cancelled: \(cancelled.reason)")
case .error(let err):
print("Error: \(err.message)")
}
}
```
Or with async/await:
```swift theme={null}
let result = await BushaPay.checkout(config: config, from: viewController)
```
```kotlin theme={null}
import co.busha.pay.BushaPay
import co.busha.pay.BushaPayConfig
import co.busha.pay.BushaPayResult
BushaPay.checkout(
activity = this,
config = BushaPayConfig(
quoteAmount = "10000",
quoteCurrency = "NGN",
targetCurrency = "NGN",
sourceCurrency = "USDT",
metaName = "Jane Doe",
metaEmail = "jane@example.com",
),
) { result ->
when (result) {
is BushaPayResult.Success -> println("Paid: ${result.paymentId}")
is BushaPayResult.Cancelled -> println("Cancelled: ${result.reason}")
is BushaPayResult.Error -> println("Error: ${result.message}")
}
}
```
The completion lambda is called exactly once, on the main thread.
```dart theme={null}
ElevatedButton(
onPressed: () {
BushaPay.checkout(
context: context,
config: BushaPayConfig(
quoteAmount: '10000',
quoteCurrency: 'NGN',
targetCurrency: 'NGN',
sourceCurrency: 'USDT',
metaName: 'John Doe',
metaEmail: 'john@example.com',
),
onComplete: (result) {
switch (result) {
case BushaPaySuccess(:final paymentId):
print('Payment $paymentId completed');
case BushaPayCancelled(:final reason):
print('Cancelled: $reason');
case BushaPayError(:final message):
print('Error: $message');
}
},
);
},
child: Text('Pay Now'),
)
```
## Platform Setup
### iOS
Add the following to `ios/YourApp/Info.plist`:
```xml theme={null}
CFBundleURLTypesCFBundleURLName$(PRODUCT_BUNDLE_IDENTIFIER).busha-payCFBundleURLSchemes$(PRODUCT_BUNDLE_IDENTIFIER).busha-payLSApplicationQueriesSchemesco.busha.appleco.busha.boro.development
```
### Android
Add the callback intent filter to your main activity in `android/app/src/main/AndroidManifest.xml`:
```xml theme={null}
```
### Expo (managed or prebuild)
In `app.json`:
```json theme={null}
{
"expo": {
"ios": {
"bundleIdentifier": "com.example.myapp",
"infoPlist": {
"LSApplicationQueriesSchemes": [
"co.busha.apple",
"co.busha.boro.development"
]
}
},
"android": {
"package": "com.example.myapp"
},
"scheme": "com.example.myapp.busha-pay"
}
}
```
For Android 11+ package visibility, install `expo-build-properties` and add this plugin:
```bash theme={null}
npx expo install expo-build-properties
```
```json theme={null}
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"android": {
"manifestQueries": {
"package": ["co.busha.android", "co.busha.android.development"]
}
}
}
]
]
}
}
```
Add the following to your `Info.plist`:
```xml theme={null}
CFBundleURLTypesCFBundleURLName$(PRODUCT_BUNDLE_IDENTIFIER).busha-payCFBundleURLSchemes$(PRODUCT_BUNDLE_IDENTIFIER).busha-payLSApplicationQueriesSchemesco.busha.appleco.busha.boro.development
```
Add an `` for the callback URL scheme to your launcher activity in `AndroidManifest.xml`. Also set `launchMode="singleTask"` so the callback reuses the existing activity instance:
```xml theme={null}
```
The required `` entries and `INTERNET` permission ship inside the
SDK's own manifest and merge into your app automatically — no extra setup
needed on your side.
### iOS
Add the following to `ios/Runner/Info.plist`:
```xml theme={null}
CFBundleURLTypesCFBundleURLName$(PRODUCT_BUNDLE_IDENTIFIER).busha-payCFBundleURLSchemes$(PRODUCT_BUNDLE_IDENTIFIER).busha-payLSApplicationQueriesSchemesco.busha.appleco.busha.boro.development
```
### Android
Add the callback intent filter to your main activity in `android/app/src/main/AndroidManifest.xml`:
```xml theme={null}
```
## Forwarding Deep Link Callbacks
The SDK does not subscribe to incoming URLs itself to avoid conflicts with your existing deep-link setup. Forward Busha callbacks with a single call — it returns `true` if the URL was a Busha callback.
Pick whichever matches the deep-link approach your app already uses.
**Option A — React Native Linking:**
```javascript theme={null}
import { useEffect } from 'react'
import { Linking } from 'react-native'
import { BushaPay } from '@busha/pay-react-native'
useEffect(() => {
const sub = Linking.addEventListener('url', ({ url }) => {
BushaPay.handleDeepLink(url)
})
Linking.getInitialURL().then((url) => {
if (url) BushaPay.handleDeepLink(url)
})
return () => sub.remove()
}, [])
```
**Option B — expo-linking:**
```javascript theme={null}
import { useEffect } from 'react'
import * as Linking from 'expo-linking'
import { BushaPay } from '@busha/pay-react-native'
useEffect(() => {
const sub = Linking.addEventListener('url', ({ url }) => {
BushaPay.handleDeepLink(url)
})
Linking.getInitialURL().then((url) => {
if (url) BushaPay.handleDeepLink(url)
})
return () => sub.remove()
}, [])
```
**Option C — React Navigation:**
```javascript theme={null}
import { NavigationContainer } from '@react-navigation/native'
import { Linking } from 'react-native'
import { BushaPay } from '@busha/pay-react-native'
const linking = {
prefixes: ['com.example.myapp.busha-pay://', 'https://yourapp.com'],
config: { /* your screens */ },
subscribe(listener) {
const sub = Linking.addEventListener('url', ({ url }) => {
if (BushaPay.handleDeepLink(url)) return
listener(url)
})
return () => sub.remove()
},
}
{/* ... */}
```
**UIKit (AppDelegate):**
```swift theme={null}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
if BushaPay.handleDeepLink(url) { return true }
return false
}
```
**UISceneDelegate (scene-based apps):**
```swift theme={null}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
for context in URLContexts {
if BushaPay.handleDeepLink(context.url) { continue }
// your own URL handling
}
}
```
**SwiftUI:**
```swift theme={null}
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
if BushaPay.handleDeepLink(url) { return }
// your own URL handling
}
}
}
}
```
Forward the callback from the activity that owns the intent filter. You need to handle both `onCreate` (cold start) and `onNewIntent` (warm start via `singleTask`):
```kotlin theme={null}
import android.content.Intent
import android.os.Bundle
import co.busha.pay.BushaPay
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
forwardBushaCallback(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
forwardBushaCallback(intent)
}
private fun forwardBushaCallback(intent: Intent?) {
val data = intent?.data?.toString() ?: return
BushaPay.handleDeepLink(data)
}
}
```
Flutter has a built-in deep-link handler that, when enabled, routes incoming URLs through your app's Router/Navigator. Whether you enable it depends on your wiring approach:
| Approach | `FlutterDeepLinkingEnabled` (iOS) / `flutter_deeplinking_enabled` (Android) |
| ------------------------------------------- | --------------------------------------------------------------------------- |
| Option A or B (Flutter Router / go\_router) | `true` — let Flutter deliver URLs to your router |
| Option C or D (app\_links / uni\_links) | `false` — otherwise Flutter and the plugin both handle the same URL |
Set the flag in your platform files:
```xml theme={null}
FlutterDeepLinkingEnabled
```
```xml theme={null}
```
**Option A — Flutter Router API:**
```dart theme={null}
class AppRouteInformationParser extends RouteInformationParser {
@override
Future parseRouteInformation(RouteInformation info) async {
final uri = info.uri;
if (BushaPay.handleDeepLink(uri)) {
return AppRoute.current();
}
return AppRoute.fromUri(uri);
}
}
```
**Option B — go\_router:**
```dart theme={null}
final router = GoRouter(
routes: [...],
redirect: (context, state) {
if (BushaPay.handleDeepLink(state.uri)) return null;
return null;
},
);
```
**Option C — app\_links:**
```dart theme={null}
import 'package:app_links/app_links.dart';
final _appLinks = AppLinks();
@override
void initState() {
super.initState();
_appLinks.uriLinkStream.listen(BushaPay.handleDeepLink);
}
```
**Option D — uni\_links:**
```dart theme={null}
import 'package:uni_links/uni_links.dart';
uriLinkStream.listen((uri) {
if (uri != null) BushaPay.handleDeepLink(uri);
});
```
You can verify your deep link setup without making a real payment.
**iOS simulator:**
```bash theme={null}
xcrun simctl openurl booted "com.example.myapp.busha-pay://callback?status=completed&paymentRequestId=PAYR_test"
```
**Android emulator:**
```bash theme={null}
adb shell am start -a android.intent.action.VIEW \
-d "com.example.myapp.busha-pay://callback?status=completed&paymentRequestId=PAYR_test"
```
Replace `com.example.myapp` with your actual bundle ID or application ID.
***
## How It Works
When `checkout()` is called, the SDK opens a chooser with two options:
1. **Pay with Busha app** — if the Busha app is installed on the device, the SDK deep-links directly into it. The user completes the payment inside the Busha app and is returned to your app via the callback URL scheme. If the Busha app is not installed, the SDK falls back to the web checkout automatically.
2. **Pay with Stablecoins** — opens the Busha web checkout in an in-app WebView (WKWebView on iOS, WebView on Android). The user completes the payment inside your app without switching to another application.
Either way, the result is delivered to the promise or callback returned by `checkout()`.
When payment completes via the **web checkout**, the result includes full payment data — amounts, currencies, exchange rate, and timeline. When payment completes via the **Busha app**, only `paymentId` and `status` are available. Use `result.hasFullData` to check before accessing the additional fields.
## Payment Results
All four SDKs return the same three result types:
| Result | Description |
| ----------- | ------------------------------------------------------------------------- |
| `success` | Payment completed. Contains `paymentId` and `status`. |
| `cancelled` | Checkout ended without a completed payment. Inspect `reason` — see below. |
| `error` | Something went wrong. Contains `message` and optional `code`. |
### Cancellation Reasons
A `cancelled` result carries a `reason` so you can tell exactly how the checkout ended:
| Reason | Meaning |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dismissed` | The user closed the in-app chooser or web checkout sheet. |
| `rejected` | The Busha app reported the user explicitly rejected the payment. `paymentId` is populated so you can reconcile the request server-side. |
| `abandoned` | The user returned from the Busha app without a callback. The outcome is unverified — the payment may still have succeeded. Always reconcile server-side via webhooks or the status API before showing the user a final state. |
When payment completes via the Busha app, only `paymentId` and `status` are
available. Full payment data (amounts, currencies, rate, timeline) is only
returned when payment completes via the web checkout. Use `result.hasFullData`
to check. Always verify payments server-side via webhooks — the client result
is a UX hint, not the source of truth.
## Checkout Configuration
| Parameter | Type | Required | Description |
| ----------------------- | ------ | -------- | ----------------------------------------------------- |
| `quoteAmount` | string | Yes | Amount to charge (e.g. `'10000'`) |
| `quoteCurrency` | string | Yes | Currency for the amount (e.g. `'NGN'`) |
| `targetCurrency` | string | Yes | Settlement currency |
| `sourceCurrency` | string | Yes | Crypto asset for payment (e.g. `'USDT'`) |
| `reference` | string | No | Custom transaction reference |
| `metaName` | string | No | Customer name |
| `metaEmail` | string | No | Customer email |
| `metaPhone` | string | No | Customer phone |
| `allowedPaymentMethods` | array | No | Restricts which payment methods are shown. See below. |
### Restricting Payment Methods
By default, checkout shows a chooser with two options: **Pay with Busha app** and **Pay with Stablecoins**. Pass `allowedPaymentMethods` to skip the chooser or restrict options:
| Value | Behaviour |
| ----------------------------------- | ------------------------------------------------------------------------------ |
| `undefined`, `null`, or `[]` | Show the full chooser |
| `['bushaApp']` / `[BUSHA_APP]` | Skip chooser; deep-link into the Busha app, with web fallback if not installed |
| `['stablecoins']` / `[STABLECOINS]` | Skip chooser; open web checkout directly |
| Multiple methods | Show the chooser with only those tiles |
## Troubleshooting
* **`CHECKOUT_IN_PROGRESS`** — A previous `checkout()` call hasn't resolved yet. Wait for it to complete before calling again.
* **`WEBVIEW_LOAD_ERROR`** — Network failure or DNS error. Check the device's internet connection.
* **`WEBVIEW_HTTP_ERROR`** — The checkout endpoint returned a non-2xx HTTP response. Check your public key and environment configuration.
* **`WEBVIEW_TIMEOUT`** — Checkout page didn't load within 30 seconds. Retry on a stable connection.
* **`HTML_LOAD_ERROR`** (iOS, Android, and Flutter only) — The bundled checkout HTML asset failed to load. Try reinstalling the SDK.
* **`WEBVIEW_PROCESS_TERMINATED`** (Android only) — The WebView renderer process was killed by the system. Retry the checkout.
* **`BUSHA_APP_LAUNCH_FAILED`** — The SDK could not deep-link into the Busha app. On iOS verify `LSApplicationQueriesSchemes` is configured correctly in your `Info.plist`. On Android verify the `` block is present in your manifest.
* **`401 Unauthorized`** — Double-check that your public API key is correct and matches your environment (sandbox vs live).
* **Callback not received after Busha app payment** — Your deep link setup is incomplete. Test it manually using the `xcrun simctl` or `adb` commands in the note above.
## What's Next?
* [How to Set Up Webhooks](/guides/webhooks/setup)
* [Accept Stablecoin with SDK Integration](/guides/accepting-stablecoin-payments/payment-widget)
* [API Reference: Payment Request Object](/api-reference/paymentrequests/create-a-payment-request)
# Accept Stablecoin with Payment Links
Source: https://docs.busha.io/guides/accepting-stablecoin-payments/payment-links
Create a Busha-hosted checkout link and share it anywhere your customers buy from you
Use Payment Links when you want to start accepting stablecoin payments quickly without building a checkout flow. Busha hosts the payment page, you share the link, and your customer completes payment in a few clicks.
**What You'll Achieve:**
1. Create a Busha payment link from your dashboard.
2. Share a hosted checkout page with customers on social, chat, or email.
3. Preview the exact payment experience before you send the link out.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business account (from the [Quick Start Guide](/guides/getting-started/quick-start)).
## How to create a payment link
Log in to Busha Business, go to **Commerce** → **Payment Links**, and click **Create Payment Link**.
Add the product or payment details your customer should see, then click **Create Payment Link**.
Copy the generated checkout URL and send it anywhere you sell from, for example, WhatsApp, Instagram, email, or SMS.
### Sample checkout link
Use this staging link to see the kind of checkout your customer receives:
`https://staging.dash.busha.io/checkout/Q4Yfew3cT8F5`
[Open the sample checkout in a new tab](https://staging.dash.busha.io/checkout/Q4Yfew3cT8F5).
## What your customer sees
The customer lands on a Busha-hosted payment page with the amount and payment details.
The customer can continue with their Busha account or pay from an external wallet.
After the customer pays, Busha shows a confirmation screen and the funds appear in your balance.
## What's Next?
* [Accept Stablecoin with SDK Integration](/guides/accepting-stablecoin-payments/payment-widget) - Add a crypto checkout directly to your website or app.
# Accept Stablecoin with SDK Integration
Source: https://docs.busha.io/guides/accepting-stablecoin-payments/payment-widget
Add Busha checkout to your website and start receiving stablecoin payments faster
Use the Busha Commerce SDK when you want customers to start a crypto payment flow from your website or web app. It gives you a ready-made checkout experience, so you can launch faster without building your own payment modal from scratch.
**What You'll Achieve:**
1. Install the Busha Commerce SDK.
2. Add a pay button to your store or checkout page.
3. Test the integration with your sandbox public key before going live.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business account (from the [Quick Start Guide](/guides/getting-started/quick-start)).
* Basic HTML and JavaScript knowledge.
* A website or web application where you want the payment button to appear.
## Live demo
Try the widget below to see the checkout flow before you integrate it:
The SDK gives you a hosted payment experience with currency conversion,
multiple crypto payment options, and built-in payment confirmation handling.
## Install the SDK
View the source code and release history on GitHub.
Choose one installation method:
**Option 1: CDN**
```html theme={null}
```
**Option 2: npm or yarn**
```bash theme={null}
npm i @busha/commerce-js
# or
yarn add @busha/commerce-js
```
```javascript theme={null}
import BushaCommerce from '@busha/commerce-js'
```
## Add the payment button
Use this example to launch the Busha checkout from your storefront:
```html theme={null}
Kemi Stores
```
## Find your public key
Your public key is available in the Busha Business dashboard:
1. Log in to your Busha Business account.
2. Go to **Settings** → **Developer Tools**.
3. Copy your **Public Key** (it starts with `pub_`).
Use your sandbox public key for testing and your production public key for
live payments.
## Test before going live
Before you switch to production:
1. Set `devMode: true`.
2. Use your sandbox public key.
3. Test a complete payment flow with a small amount.
4. Confirm your `onSuccess` callback runs as expected.
5. Check that the payment appears in your Busha dashboard.
```javascript theme={null}
BushaCommerce({
public_key: 'pub_sandbox_key_here',
quote_amount: '1000',
quote_currency: 'NGN',
target_currency: 'NGN',
source_currency: 'USDT',
devMode: true,
meta: {
name: 'Kemi Stores',
email: 'orders@kemistore.com',
},
onSuccess: (data) => {
console.log('Payment successful!', data)
},
onClose: () => {
console.log('Payment cancelled')
},
})
```
## Configuration reference
### Required settings
| Parameter | Type | Description |
| ----------------- | -------- | --------------------------------------------------- |
| `public_key` | string | Your Busha Business public key (starts with `pub_`) |
| `quote_amount` | string | Amount to charge, for example `10000` |
| `quote_currency` | string | Currency for the quoted amount, for example `NGN` |
| `source_currency` | string | Asset the customer pays with, for example `USDT` |
| `target_currency` | string | Currency the payment settles into |
| `onSuccess` | function | Runs when the payment succeeds |
| `onClose` | function | Runs when the checkout modal closes |
### Useful optional settings
| Parameter | Type | Description |
| -------------- | ------- | --------------------------------------------------- |
| `meta.name` | string | Customer or order name shown in your integration |
| `meta.email` | string | Customer email for order context |
| `devMode` | boolean | Set to `true` for sandbox testing |
| `reference` | string | Your custom transaction reference |
| `callback_url` | string | URL to receive payment notifications |
| `source` | string | Source label for the payment, for example `website` |
| `source_id` | string | Internal ID tied to the payment source in your app |
## What's Next?
* [Accept Stablecoin with Payment Links](/guides/accepting-stablecoin-payments/payment-links) - Use a hosted checkout when you do not want to build a website flow yet.
* [Quick Start Guide](/guides/getting-started/quick-start) - Set up your Busha Business account.
# Convert Between Balances
Source: https://docs.busha.io/guides/balance/convert-balance-to-balance
Convert funds between currencies in your Busha account. Swap NGN to USDT, BTC to KES, and more.
This guide will show you how to programmatically convert one cryptocurrency into another within your Busha Business account (e.g., USDT to BTC). All conversions on Busha are processed as transfers, which always begin with a Quote to define the conversion terms.
**What You'll Achieve:**
1. Understand the specific quote requirements for crypto conversions.
2. Generate a conversion quote.
3. Execute the crypto-to-crypto conversion transfer.
4. Confirm the status of the conversation.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start))
* An understanding of the **API Environments** (Sandbox vs. Production) and their respective base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
* A conceptual understanding of **Quotes** (from the [Understanding Quotes](/overview/quotes) Overview).
* Familiarity with creating basic quotes (from the [How to Create Your First Quote](/guides/quotes/create-first-quote) Guide).
For conversion requests involving a customer, the `X-BU-PROFILE-ID` field
should be included in the request header, and its value should be set to the
customer ID for whom the request is performed on their behalf.
## How to Convert Crypto to Crypto
The first step in any conversion is to create a Quote. This specifies the `source_currency` (what you're converting from) and `target_currency` (what you're converting to). You must provide either the `source_amount` or the `target_amount`, but not both.
To create a conversion quote:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/quotes` endpoint.
3. Specify the `source_currency`, `target_currency`, and either `source_amount` (as shown below) or `target_amount`. Make sure to set the type to "convert".
4. Replace `YOUR_BASE_URL` with your chosen environment's URL, `YOUR_SECRET_TOKEN` with your actual key, and `BUS_YOK8tp5Zga01qOKEsqp07` with your actual `X-BU-PROFILE-ID`.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-H 'X-BU-PROFILE-ID: BUS_YOK8tp5Zga01qOKEsqp07' \
-d '{
"source_currency": "USDT",
"target_currency": "BTC",
"source_amount": "20"
}'
```
**Expected Quote Response**
A successful response will return a Quote object containing the `id`, calculated `target_amount` (if you provided `source_amount`), the rate for the conversion, and its `expires_at` timestamp. Note the `id` of this quote (e.g., `QUO_Nm2EBRxmuHGdTyGnVNDUt`), as you'll need it for the next step.
Once you have a valid Quote ID, you can proceed to execute the conversion by creating a transfer. This action consumes the quote and initiates the actual asset exchange.
To create the conversion transfer:
1. Use the `POST` request below to the `/v1/transfers` endpoint.
2. Include the `quote_id` obtained from Step 1 in the request body.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_Nm2EBRxmuHGdTyGnVNDUt"
}'
```
**Expected Transfer Response**
A successful response indicates that the transfer has been initiated. For conversions, the transaction is typically processed very quickly, often immediately. The response will include a `id` (e.g., `TRF_oBoehqd2KVt1wcadB8wz5`) and the initial status of the transfer (likely `pending` or `completed` almost instantly).
Although conversion transfers are usually processed immediately, it's good practice to confirm their final status. You can do this by retrieving the transfer details using its ID.
To confirm the transfer status:
1. Use the `GET` request below to the `/v1/transfers/{id}` endpoint.
2. Replace `{id}` with the actual `transfer_id` you received in Step 2.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```bash theme={null}
$ curl -i -X GET \
https://YOUR_BASE_URL/v1/transfers/TRF_oBoehqd2KVt1wcadB8wz5 \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'
```
**Expected Statuses**
* **completed:** The conversion was successful, and your `target_currency` balance has been updated.
* **failed:** The conversion failed (e.g., insufficient balance, quote expired before execution).
* **pending:** (Less common for conversions, but possible briefly) The transfer is still being processed.
For real-time updates, setting up webhooks is recommended, as they will notify you automatically when the transfer status changes.
A trade is a type of conversion that represents a buy or sell action from or to Busha Fiat Wallet against a Busha crypto asset.
A trade works just the same as a conversion, except that either of the `source_currency` and `target_currency` could be a fiat currency (e.g., NGN, KES).
## Troubleshooting
**Common Conversion Issues:**
* **"Quote expired" during transfer creation:** Always generate a fresh quote immediately before attempting to create the transfer.
* **"Insufficient balance":** Ensure your Busha account has enough `source_currency` to cover the `source_amount` in the quote.
* **Invalid currency pair:** Double-check that Busha supports direct conversion between your chosen `source_currency` and `target_currency`.
* **401 Unauthorized:** Verify your Authorization header and API key.
## What's Next?
Now that you understand balance-to-balance conversions, you can explore other transaction types:
* [How to Create Your First Quote Guide](/guides/quotes/create-first-quote)
* [How to Process Fiat Deposits Guide](/guides/deposits/process-fiat-deposits)
* [How to Process Crypto Deposits Guide](/guides/deposits/process-crypto-deposits)
* [Quotes API Reference](/api-reference/quotes/list-quotes)
* [Transfers API Reference](/api-reference/transfers/list-transfers)
# Manage Balance Accounts
Source: https://docs.busha.io/guides/balance/manage-balance-accounts
View and manage multi-currency balances. Check NGN, KES, USDT, BTC, and other currency balances.
Balance accounts on Busha are designed to hold specific currencies, making them a crucial component for managing your multi-currency transactions. This guide will walk you through the process of programmatically creating new balance accounts and retrieving existing ones via the Busha API.
**What You'll Achieve:**
1. Learn how to create a new balance account for a specific currency
2. Understand how to retrieve a list of all your existing balance accounts
3. Confirm successful API interactions for managing currency balances
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start))
* An understanding of the **API Environments** (Sandbox vs. Production) and their respective base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
## Managing Your Balance Accounts
Before creating a balance account, you must know which currencies Busha currently supports. This ensures your requests are valid.
To find supported currencies:
* Refer to the Supported Currencies Reference for the most up-to-date list of available currency codes.
* When presenting a currency options to your customers, ensure you only display those returned by Busha's API or listed in our documentation to prevent invalid requests.
To view a comprehensive list of all existing balance accounts associated with your business, use a GET request. This is useful for displaying current balances or iterating through available currencies.
To retrieve balance accounts:
1. Open your terminal or command prompt
2. Use the `GET` request below, replacing the placeholders:
* `YOUR_BASE_URL`: Use your chosen environment's base URL.
* `{YOUR_SECRET_API_KEY}`: Your actual Secret API Key.
```shell theme={null}
$ curl --request GET \
--url YOUR_BASE_URL/v1/balances \
--header 'Authorization: Bearer {YOUR_SECRET_API_KEY}' \
--header 'Content-Type: application/json'
```
**Expected Response**
A successful response will return a JSON object containing an array of all your balance accounts.
```json theme={null}
{
"status": "success",
"message": "Fetched balances successfully",
"data": [
{
"id": "96da4899-ff99-4821-88df-5182b8d37300",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "GHS",
"name": "Cedi",
"type": "fiat",
"available": {
"amount": "0",
"currency": "GHS"
},
"pending": {
"amount": "0",
"currency": "GHS"
},
"total": {
"amount": "0",
"currency": "GHS"
}
},
{
"id": "05320e5e-a8ff-48e4-ac0b-23f7b1aa14d7",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "KES",
"name": "Shilling",
"type": "fiat",
"available": {
"amount": "0",
"currency": "KES"
},
"pending": {
"amount": "0",
"currency": "KES"
},
"total": {
"amount": "0",
"currency": "KES"
}
},
{
"id": "960ab09d-cd55-4118-8b6e-c12b340efec3",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "NGN",
"name": "Naira",
"type": "fiat",
"available": {
"amount": "0",
"currency": "NGN"
},
"pending": {
"amount": "0",
"currency": "NGN"
},
"total": {
"amount": "0",
"currency": "NGN"
}
},
{
"id": "1ebeabb4-6e4f-449f-8c0f-18a9c9d9187a",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USD",
"name": "US Dollar",
"type": "fiat",
"available": {
"amount": "0",
"currency": "USD"
},
"pending": {
"amount": "0",
"currency": "USD"
},
"total": {
"amount": "0",
"currency": "USD"
}
},
{
"id": "bc1dfeae-055e-4d4e-a583-0c8030e5a1cd",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "BTC",
"name": "Bitcoin",
"type": "crypto",
"available": {
"amount": "0",
"currency": "BTC"
},
"pending": {
"amount": "0",
"currency": "BTC"
},
"total": {
"amount": "0",
"currency": "BTC"
}
},
{
"id": "b8dbf5e4-4d1f-4489-81fe-2a5e1e9816e1",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "ETH",
"name": "Ethereum",
"type": "crypto",
"available": {
"amount": "0",
"currency": "ETH"
},
"pending": {
"amount": "0",
"currency": "ETH"
},
"total": {
"amount": "0",
"currency": "ETH"
}
},
{
"id": "ec5744b6-ab06-4180-b354-e672b9a5f30a",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USDC",
"name": "USD Coin",
"type": "crypto",
"available": {
"amount": "0",
"currency": "USDC"
},
"pending": {
"amount": "0",
"currency": "USDC"
},
"total": {
"amount": "0",
"currency": "USDC"
}
},
{
"id": "fb891621-0b15-45f5-9b81-ea3995cbf891",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USDT",
"name": "USD Token",
"type": "crypto",
"available": {
"amount": "0",
"currency": "USDT"
},
"pending": {
"amount": "0",
"currency": "USDT"
},
"total": {
"amount": "0",
"currency": "USDT"
}
}
],
"pagination": {
"current_entries_size": 8
}
}
```
## Troubleshooting
* **`401 Unauthorized Request`:** Double-check your API key.
## What's Next?
Now that you know how to retrieve balance accounts, you can:
* Explore all related endpoints and data structures in detail: [Multi-Currency Accounts API Reference](/api-reference/balances/list-all-balances)
# Create a Business Customer
Source: https://docs.busha.io/guides/customers/create-business
Set up business customer accounts. Manage company profiles and business verification.
This guide provides a technical walkthrough on programmatically creating a business customer account within your Busha Business account using the Busha API. By automating customer creation, you can streamline your onboarding processes and prepare to perform transactions on behalf of your customers.
**What You'll Achieve:**
1. Understand the basic structure for creating a business customer.
2. Learn how to structure API requests for the business customer type.
3. Successfully create and verify business customer accounts programmatically.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
## Creating a Business Customer Account
The essential parameters for creating a business customer are:
Parameter
Type
Example Value
Description
email
string
business@gmail.com
The primary email address for the business contact.
has\_accepted\_terms
boolean
true
Indicates if the terms and conditions have been accepted.
type
string
business
The type of customer being created.
country\_id
string
NG
The ISO 3166-1 alpha-2 country code of the business's operation.
phone
string
+234 8012345678
The business's primary contact phone number, including country code.
birth\_date
string
01-01-2015
The incorporation date or a key date associated with the business.
address
object
See details below
The business's physical address details.
business\_name
string
ABC Corporation
The legal registered name of the business.
business\_industry
string
BIN\_C4UvTYR5V8jsOx5LmwQ
A unique identifier representing the business's industry.
business\_incorporation\_date
string
2015-06-15
The date on which the business was officially incorporated.
For `business_industry`, the list of supported sectors and their unique identifier can be retrieved from [Supported Business Industries](/guides/reference/supported-industries).
**Address Object:**
The `address` field requires:
```json theme={null}
"address": {
"country_id": "NG",
"address_line_1": "123 Business Avenue",
"city": "Lagos",
"state": "Lagos"
}
```
**Know Your Business (KYB)**
For full verification, business customers require additional sections:
1. **Documents** - Business registration documents
2. **Business Owners** - Information about directors and beneficial owners
3. **Business Transaction** - Expected transaction patterns
4. **Business Registration** - Legal and regulatory information
Files uploaded for KYB must be in Base64 format and have a file size less than
4MB.
**Business Owners:**
```json theme={null}
"business_owners": [
{
"first_name": "John",
"last_name": "Doe",
"role": ["director"],
"percentage_ownership": 100,
"is_pep": false,
"nationality": "NG",
"bvn": "12345678901"
}
]
```
**Business Transaction:**
```json theme={null}
"business_transaction": {
"purpose": "international trade",
"monthly_transaction_value": "above_1m_usd",
"monthly_transaction_count": "100_to_200",
"client_transaction_status": "self-owned",
"api_access_needed": true,
"api_integration_url": "https://yourbusiness.com"
}
```
**Business Registration:**
```json theme={null}
"business_registration": {
"business_type": "type_registered_company",
"business_structure": "limited_liability_company",
"business_regulation_status": "regulated",
"registration_number": "RC1234567",
"tax_identification_number": "TIN1234567",
"corporate_group_status": "standalone_company",
"exchange_listing_status": "not_listed_on_exchange",
"license_number": "LIC123456"
}
```
**Documents:**
```json theme={null}
"documents": [
{
"purposes": ["certificate_of_incorporation"],
"file": "{{base64 string}}"
}
]
```
For a full list of acceptable documents, please refer to the [Compliance Guide](/overview/compliance).
Business customers represent legal entities that utilize your offerings. Start with basic information and add KYB details later.
To create a business customer without KYB documents:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "business.basic@gmail.com",
"has_accepted_terms": true,
"type": "business",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "01-01-2015",
"address": {
"country_id": "NG",
"address_line_1": "123 Business Avenue",
"city": "Lagos",
"state": "Lagos"
},
"business_name": "Basic Corp",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_incorporation_date": "2015-06-15"
}'
```
**Expected Response:**
A successful response will return a Customer object with `status: "inactive"` until KYB is completed.
```json theme={null}
{
"status": "success",
"message": "Created customer successfully",
"data": {
"address": {
"address_line_1": "123 Business Avenue",
"city": "Lagos",
"country_id": "NG",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"business_incorporation_date": "2015-06-15",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_name": "Basic Corp",
"country_id": "NG",
"created_at": "2026-01-27T13:00:16.152775472Z",
"deposit": true,
"display_currency": "NGN",
"email": "business.basic@gmail.com",
"has_accepted_terms_of_service": true,
"id": "CUS_B912WgfXH0I4U",
"level": "0",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "business",
"updated_at": "2026-01-27T13:00:16.152775472Z"
}
}
```
The default status of a customer is `inactive` until they complete their Know-Your-Business (KYB) process.
Create a fully verified business customer by including all required KYB sections at creation.
To create a business customer with complete KYB:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "abccorp.verified@gmail.com",
"has_accepted_terms": true,
"type": "business",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "01-01-2015",
"address": {
"country_id": "NG",
"address_line_1": "123 Business Avenue",
"city": "Lagos",
"state": "Lagos"
},
"business_name": "ABC Corporation",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_incorporation_date": "2015-06-15",
"documents": [
{
"purposes": ["certificate_of_incorporation"],
"file": "{{base64 encoded certificate}}"
}
],
"business_owners": [
{
"first_name": "Abdulazeez",
"last_name": "Abdulazeez",
"role": ["director"],
"percentage_ownership": 100,
"is_pep": false,
"nationality": "NG",
"bvn": "12345678901"
}
],
"business_transaction": {
"purpose": "international trade",
"monthly_transaction_value": "above_1m_usd",
"monthly_transaction_count": "100_to_200",
"client_transaction_status": "self-owned",
"api_access_needed": true,
"api_integration_url": "https://abccorp.com"
},
"business_registration": {
"business_type": "type_registered_company",
"business_structure": "limited_liability_company",
"business_regulation_status": "regulated",
"registration_number": "RC8828228",
"tax_identification_number": "2277711991",
"corporate_group_status": "standalone_company",
"exchange_listing_status": "not_listed_on_exchange",
"license_number": "8383838"
}
}'
```
**Expected Response:**
```json theme={null}
{
"status": "success",
"message": "Created customer successfully",
"data": {
"address": {
"address_line_1": "123 Business Avenue",
"city": "Lagos",
"country_id": "NG",
"state": "Lagos"
},
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_incorporation_date": "2015-06-15",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_name": "ABC Corporation",
"country_id": "NG",
"created_at": "2026-01-27T13:00:16.152775472Z",
"deposit": true,
"display_currency": "NGN",
"email": "abccorp.verified@gmail.com",
"has_accepted_terms_of_service": true,
"id": "CUS_BstLqfzSrdQEd",
"level": "0",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "business",
"updated_at": "2026-01-27T13:00:16.152775472Z"
}
}
```
After creating a customer with complete KYB information, verify them to activate their account.
To verify a business customer:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers/{customer_id}/verify` endpoint.
3. Replace `{customer_id}` with the customer ID from the previous response.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers/CUS_BstLqfzSrdQEd/verify \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}'
```
**Expected Response:**
A successful verification will return:
```json theme={null}
{
"status": "success",
"message": "Customer verified successfully"
}
```
After verification, check the customer status by retrieving their details. The status will change from `inactive` to `in_review` or `active`.
**Common Errors:**
* **missing\_section (Owners):** Business owners section is incomplete
* **missing\_section (Transaction):** Transaction information is missing
* **missing\_documents:** Required KYB documents are not uploaded
If you receive a `missing_section` error, update the customer with the required information using the `PUT /v1/customers/{customer_id}` endpoint, then retry verification.
## Complete Example: Create and Verify Business Customer
Here's a complete workflow to create and verify a business customer in one go:
**Step 1: Create customer with complete KYB**
```shell theme={null}
curl -X POST https://api.sandbox.busha.so/v1/customers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"email": "verified.business@gmail.com",
"has_accepted_terms": true,
"type": "business",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "01-01-2015",
"address": {
"country_id": "NG",
"address_line_1": "456 Corporate Plaza",
"city": "Lagos",
"state": "Lagos"
},
"business_name": "Verified Corp Ltd",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_incorporation_date": "2015-06-15",
"documents": [
{
"purposes": ["certificate_of_incorporation"],
"file": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}
],
"business_owners": [
{
"first_name": "Jane",
"last_name": "Director",
"role": ["director"],
"percentage_ownership": 100,
"is_pep": false,
"nationality": "NG",
"bvn": "12345678901"
}
],
"business_transaction": {
"purpose": "e-commerce",
"monthly_transaction_value": "above_1m_usd",
"monthly_transaction_count": "100_to_200",
"client_transaction_status": "self-owned",
"api_access_needed": true,
"api_integration_url": "https://verifiedcorp.com"
},
"business_registration": {
"business_type": "type_registered_company",
"business_structure": "limited_liability_company",
"business_regulation_status": "regulated",
"registration_number": "RC9999999",
"tax_identification_number": "TIN9999999",
"corporate_group_status": "standalone_company",
"exchange_listing_status": "not_listed_on_exchange",
"license_number": "LIC999999"
}
}'
```
**Step 2: Verify the customer**
```shell theme={null}
curl -X POST https://api.sandbox.busha.so/v1/customers/CUS_xxx/verify \
-H 'Authorization: Bearer YOUR_SECRET_KEY'
```
**Step 3: Check customer status**
```shell theme={null}
curl -X GET https://api.sandbox.busha.so/v1/customers/CUS_xxx \
-H 'Authorization: Bearer YOUR_SECRET_KEY'
```
Expected status: `"status": "in_review"` or `"status": "active"`
***
## Troubleshooting
* **400 Bad Request / 422 Unprocessable Entity:** Review your request body to ensure all required fields are present and correctly formatted for the specified type (individual or business).
* **401 Unauthorized:** Verify that your Secret API Key is correct and included in the header.
* **Email validation error:** Use real email domains like `@gmail.com` instead of generic domains like `@example.com`.
* **missing\_section errors during verification:** Ensure all required sections (owners, transaction, registration) are included before calling verify.
## What's Next?
Now that you can programmatically create and verify business customers, you can proceed to manage them and perform transactions on their behalf:
* [How to Create an Individual Customer](/guides/customers/create-individual): Learn how to create an individual customer in your Busha business account.
* [How to Verify Customer's Identity (KYC/KYB)](/guides/customers/verify-identity): Learn more about the verification process and required documents.
* [How to Initiate Transactions on Behalf of a Customer](/guides/customers/transactions-on-behalf): Understand how to use the `customer_id` to perform operations for your customers.
# Create an Individual Customer
Source: https://docs.busha.io/guides/customers/create-individual
Create customer profiles for individual users. Handle KYC and identity verification.
This guide provides a technical walkthrough on programmatically creating an individual customer account within your Busha Business account using the Busha API. By automating customer creation, you can streamline your onboarding processes and prepare to perform transactions on behalf of your customers.
**What You'll Achieve:**
1. Understand the basic structure for creating a customer.
2. Learn how to structure API requests for individual customer types.
3. Successfully create and verify customer accounts programmatically.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of **API Environments** (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
## Creating an Individual Customer Account
The essential parameters for creating an individual customer type are:
Parameter
Type
Description
email
string
The individual customer's email address.
has\_accepted\_terms
boolean
A flag indicating whether the individual has accepted your platform's
(or Busha's) terms and conditions.
type
string
The type of customer. Must be individual for this customer
type.
country\_id
string
The ISO 3166-1 alpha-2 country code representing the individual's
primary country of residence.
phone
string
The individual's phone number, including the international country code
(e.g., +234 8012345678).
birth\_date
string
The individual's date of birth, typically required for identity
verification. Format: DD-MM-YYYY.
first\_name
string
The individual customer's first name.
middle\_name
string
The individual customer's middle name (optional).
last\_name
string
The individual customer's last name.
address
object
The individual's physical address details. See the Address Object
Parameters table below for nested fields.
identifying\_information
array
An array of objects describing the individual's identification documents
and selfie image (e.g., passport + selfie, national ID + selfie).
For the `address` field in the customer creation object, the fields required are:
Parameter
Type
Description
city
string
The city component of the address.
state
string
The state or region component of the address.
county
string
The county or district component of the address (optional).
country\_id
string
The ISO 3166-1 alpha-2 country code of the address.
address\_line\_1
string
The first line of the street address.
address\_line\_2
string
The second line of the street address (optional).
province
string
The province component of the address (optional).
postal\_code
string
The postal or ZIP code of the address.
**Know Your Customer (KYC)**
Optionally, you can choose to upload your customer's KYC documents at the point of creation in the `identifying_information` array field.
Files uploaded for KYC must be in Base64 format and have a file size less than
4MB.
**KYC Document Requirements:**
For individual customers, you must provide ONE of the following combinations in the `identifying_information` array:
**Option 1: Passport + Selfie**
```json theme={null}
"identifying_information": [
{
"type": "passport",
"number": "passport-number",
"country": "NG",
"image_front": "{{base64 encoded passport image}}"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
```
**Option 2: National ID + Selfie**
```json theme={null}
"identifying_information": [
{
"type": "national-id",
"number": "id-number",
"country": "NG"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
```
Country
Documents Required
Nigeria
NIN number and selfie image
National passport and selfie image
Driver's license and selfie image
Kenya
National ID and selfie image
For a full list of acceptable documents, please refer to the [Compliance Guide](/overview/compliance).
**Adding a BVN**
You can optionally include a customer's Bank Verification Number (BVN) as an additional entry in `identifying_information`:
```json theme={null}
"identifying_information": [
{
"type": "bvn",
"number": "12345678901",
"country": "NG"
}
]
```
A BVN is not required for standard KYC verification, but it is required if you want to generate a virtual NGN bank account for the customer via [`GET /v1/virtual_bank_accounts/{code}`](/api-reference/miscellaneous/get-virtual-bank-account). Attempting to request a virtual bank account for a customer without a BVN on file returns an `err_bvn_verification_required` error. You can add a BVN at creation time using the payload above, or afterward using `PUT /v1/customers/{customer_id}`.
Individual customers refer to persons who engage with your services. Start with basic information and add KYC documents later.
To create an individual customer without KYC documents:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer.basic@gmail.com",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "24-12-2000",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "10 Allen Avenue",
"postal_code": "100001"
},
"first_name": "John",
"last_name": "Doe"
}'
```
**Expected Response:**
A successful response will return a Customer object with `status: "inactive"` until KYC is completed.
The default status of a customer is `inactive` until they complete their Know-Your-Customer (KYC) process.
```json theme={null}
{
"status": "success",
"message": "Created customer successfully",
"data": {
"address": {
"address_line_1": "10 Allen Avenue",
"city": "Lagos",
"country_id": "NG",
"postal_code": "100001",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"country_id": "NG",
"created_at": "2026-01-27T09:23:09.317273Z",
"deposit": true,
"display_currency": "NGN",
"email": "customer.basic@gmail.com",
"first_name": "John",
"has_accepted_terms_of_service": true,
"id": "CUS_IL2Qf2pEoNADZ",
"last_name": "Doe",
"level": "0",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "individual",
"updated_at": "2026-01-27T09:23:09.317273Z"
}
}
```
Create a verified customer by including KYC documents at creation.
To create a customer with supporting KYC documents:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
**Example with Passport + Selfie:**
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "jacob.verified@gmail.com",
"first_name": "Jacob",
"last_name": "Zuma",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8087654321",
"birth_date": "24-12-1990",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "15 Victoria Island",
"postal_code": "100001"
},
"identifying_information": [
{
"type": "passport",
"number": "passport-number",
"country": "NG",
"image_front": "{{base64 encoded passport image}}"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
}'
```
**Example with National ID + Selfie:**
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "jacob.verified@gmail.com",
"first_name": "Jacob",
"last_name": "Zuma",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8087654321",
"birth_date": "24-12-1990",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "15 Victoria Island",
"postal_code": "100001"
},
"identifying_information": [
{
"type": "national-id",
"number": "id-number",
"country": "NG"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
}'
```
**Expected Response:**
```json theme={null}
{
"status": "success",
"message": "Created customer successfully",
"data": {
"address": {
"address_line_1": "15 Victoria Island",
"city": "Lagos",
"country_id": "NG",
"postal_code": "100001",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"country_id": "NG",
"created_at": "2026-01-27T09:23:09.317273Z",
"deposit": true,
"display_currency": "NGN",
"email": "jacob.verified@gmail.com",
"first_name": "Jacob",
"has_accepted_terms_of_service": true,
"id": "CUS_Ikdb49NLsnlYU",
"last_name": "Zuma",
"level": "0",
"payout": true,
"phone": "+234 8087654321",
"status": "inactive",
"type": "individual",
"updated_at": "2026-01-27T09:23:09.317273Z"
}
}
```
The status remains `inactive` until the documents are verified. Call the verify endpoint to submit for verification.
After creating a customer with KYC documents, verify them to activate their account.
To verify a customer:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers/{customer_id}/verify` endpoint.
3. Replace `{customer_id}` with the customer ID from the previous response.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers/CUS_Ikdb49NLsnlYU/verify \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}'
```
**Expected Response:**
A successful verification will return:
```json theme={null}
{
"status": "success",
"message": "Customer verified successfully"
}
```
After verification, check the customer status. It will change from `inactive` to `in_review` or `active`.
**Common Errors:**
* **`profile_kyc_verification`:** KYC documents are missing or incomplete (e.g., no selfie image)
If you receive this error, update the customer with the missing documents using `PUT /v1/customers/{customer_id}`, then retry verification.
## Complete Example: Create and Verify Customer
Here's a complete workflow to create and verify an individual customer:
**Step 1: Create customer with KYC documents (Passport + Selfie)**
```shell theme={null}
curl -X POST https://api.sandbox.busha.so/v1/customers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"email": "verified.customer@gmail.com",
"first_name": "Test",
"last_name": "Customer",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "15-06-1990",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "10 Allen Avenue",
"postal_code": "100001"
},
"identifying_information": [
{
"type": "passport",
"number": "passport-number",
"country": "NG",
"image_front": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
},
{
"type": "selfie",
"image_front": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"number": "",
"country": "NG"
}
]
}'
```
**Step 2: Verify the customer**
```shell theme={null}
curl -X POST https://api.sandbox.busha.so/v1/customers/CUS_xxx/verify \
-H 'Authorization: Bearer YOUR_SECRET_KEY'
```
**Step 3: Check customer status**
```shell theme={null}
curl -X GET https://api.sandbox.busha.so/v1/customers/CUS_xxx \
-H 'Authorization: Bearer YOUR_SECRET_KEY'
```
Expected status: `"status": "in_review"` or `"status": "active"`
**Customer Status Flow:** 1. `inactive` - Default status after creation 2.
`in_review` - After calling verify endpoint with valid documents 3. `active` -
After verification approval (automatic in sandbox, manual review in
production)
***
## Troubleshooting
* **400 Bad Request / 422 Unprocessable Entity:** Review your request body to ensure all required fields are present and correctly formatted.
* **401 Unauthorized:** Verify that your Secret API Key is correct and included in the header.
* **Email validation error:** Use real email domains like `@gmail.com` instead of generic domains like `@example.com`.
* **`profile_kyc_verification` error during verification:** Ensure all required documents (ID images and selfie image) are uploaded before calling verify.
* **`err_bvn_verification_required` when requesting a virtual bank account:** The customer doesn't have a BVN on file. Add one via `PUT /v1/customers/{customer_id}` using the `bvn` type in `identifying_information`, then retry.
## What's Next?
Now that you can programmatically create and verify individual customers, you can proceed to manage them and perform transactions on their behalf:
* [How to Create a Business Customer](/guides/customers/create-business): Learn how to create a business customer in your Busha business account.
* [How to Verify Customer's Identity (KYC/KYB)](/guides/customers/verify-identity): Learn more about the verification process and required documents.
* [How to Initiate Transactions on Behalf of a Customer](/guides/customers/transactions-on-behalf): Understand how to use the `customer_id` to perform operations for your customers.
* [Webhook Events](/guides/webhooks/webhook-events): Learn about customer verification webhook events.
# Retrieve Customers
Source: https://docs.busha.io/guides/customers/retrieve-customers
Fetch customer profiles and details. Access KYC status, balances, and transaction history.
After creating customers, you'll often need to retrieve their details or get a list of all customers associated with your business account. This allows you to manage operations and ensure you're using the correct `customer_id` for transactions.
This guide provides a technical walkthrough on retrieving the customers associated with your Busha business account via the Busha API
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** ([from the Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of **API Environments** (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
## How to Retrieve Customer Information
You can fetch the details of a single customer from their ID.
To retrieve a specific customer:
1. Open your terminal or command prompt.
2. Construct a `GET` request to the `/v1/customers/{customer_id}` endpoint, replacing `{customer_id}` with the actual customer ID.
3. Ensure your `Authorization` and `YOUR_SECRET_TOKEN` headers are included.
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN`.
```shell theme={null}
$ curl -i -X GET "https://YOUR_BASE_URL/v1/customers/{id}" \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json'
```
**Expected Response:**
A successful response will return a single customer object, identical in structure to the one received during creation, containing all its details:
```json theme={null}
{
"status": "success",
"message": "Fetched customer successfully",
"data": {
"address": {
"address_line_1": "RT Lawal",
"address_line_2": "",
"city": "Lekki",
"country_id": "NG",
"county": "Mombasa",
"postal_code": "12345",
"province": "province",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"country_id": "NG",
"created_at": "2025-06-25T22:08:08.978994Z",
"deposit": true,
"display_currency": "NGN",
"email": "trybusha@busha.so",
"first_name": "Busha",
"has_accepted_terms_of_service": true,
"id": "CUS_IL2Qf2pEoNADZ",
"last_name": "Mascot",
"middle_name": "Crypto",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "individual",
"updated_at": "2025-06-25T22:08:08.978994Z"
}
}
```
To get an overview of all the customers you have created, you can make a `GET` request to the `/v1/customers` endpoint without specifying an ID.
To list all customers:
1. Open your terminal or command prompt.
2. Construct a `GET` request to the `/v1/customers` endpoint.
3. Ensure your `Authorization` header is included.
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN`.
```shell theme={null}
$ curl -i -X GET 'https://YOUR_BASE_URL/v1/customers' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'
```
**Expected Response**
A successful response will return a list (an array) of all recipient objects associated with your account.
```json theme={null}
{
"status": "success",
"message": "Fetched customers successfully",
"data": [
{
"address": {
"address_line_1": "RT Lawal",
"address_line_2": "",
"city": "Lekki",
"country_id": "NG",
"county": "Mombasa",
"postal_code": "12345",
"province": "province",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"country_id": "NG",
"created_at": "2025-06-25T22:08:08.978994Z",
"deposit": true,
"display_currency": "NGN",
"email": "trybusha@busha.co",
"first_name": "Busha",
"has_accepted_terms_of_service": true,
"id": "CUS_IL2Qf2pEoNADZ",
"last_name": "Mascot",
"middle_name": "Crypto",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "individual",
"updated_at": "2025-06-25T22:08:08.978994Z"
}
],
"pagination": {
"current_entries_size": 1,
"previous_cursor": "MDAwMS0wMS0wMVQwMDowMDowMFo="
}
}
```
## Troubleshooting
* **404 Not Found:** Verify that the customer ID is correct.
* **401 Unauthorized:** Verify that your Secret API Key is correct and included in the header.
## What's Next?
Now that you can retrieve customers, you can proceed to manage them and perform transactions on their behalf:
* [How to Verify Customer's Identity (KYC/KYB)](/guides/customers/verify-identity): Learn how to conduct and verify the identity of your customer to allow them full access to Busha's operations.
* [How to Initiate Transactions on Behalf of a Customer](/guides/customers/transactions-on-behalf): Understand how to use the `customer_id` to perform operations for your customers.
# Initiate Transactions on Behalf of Customers
Source: https://docs.busha.io/guides/customers/transactions-on-behalf
Process deposits, payouts, and conversions for your customers.
Businesses can perform any transaction on behalf of a customer that the customer could perform themselves. To do this, the **customer's profile ID** must be included in the header. This ensures the transaction is correctly attributed to the customer rather than the business's account.
For transaction requests involving a customer, the `X-BU-PROFILE-ID` field
should be included in the request header, and its value should be set to the
customer ID for whom the request is performed on their behalf.
This guide will walk you through the process of programmatically accepting fiat currency deposits (e.g., NGN, KES) into your customer's Busha Business fiat balances. Fiat deposits are typically facilitated through the generation of temporary bank accounts.
**What You'll Achieve:**
1. Understand the specific quote requirements for fiat deposits.
2. Generate a deposit quote that provisions a temporary bank account.
3. Finalize the deposit transfer to obtain the temporary bank account details.
4. Learn how to instruct your customer to make the deposit.
5. Monitor the status of fiat deposits.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
* A conceptual understanding of Quotes (from the [Quotes Overview](/overview/quotes)).
* Familiarity with creating basic quotes (from the [How to Create Your First Quote](/guides/quotes/create-first-quote) Guide)
* A customer account.
## Processing Transactions on Behalf of Customers
Fiat deposits are initiated by creating a Quote, where the `source_currency` and `target_currency` are the same fiat currency (e.g., NGN to NGN). The key here is the `pay_in` object, which specifies that you intend to use a `temporary_bank_account` for the deposit. This informs Busha to prepare for generating such an account upon transfer finalization.
**To get a fiat deposit quote:**
1. Open your terminal or command prompt.
2. Construct a POST request to the `/v1/quotes` endpoint.
3. Specify the `source_currency` and `target_currency` (both being the fiat currency you expect to receive), the `source_amount` the customer intends to deposit, and a `pay_in` object with `type: "temporary_bank_account"`.
4. Replace `{customer_id}` with the customer ID.
5. Replace `YOUR_BASE_URL` with your chosen environment's URL and `YOUR_SECRET_TOKEN` with your actual key.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'X-BU-PROFILE-ID: {customer_id}' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "10000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
A successful response will return a standard Quote object, similar to what you've seen before.
Note the `id` of the returned Quote (e.g., `QUO_vxcF2svmjMbxDp4T5dcD8`), as
you will need this ID for the next step.
The `pay_in` object in the quote response will mirror what you sent in the request.
After obtaining a valid Quote for a fiat deposit, you finalize the transfer. This crucial step is where Busha *generates* the temporary bank account details that your customer will transfer funds into. The transfer object is initiated using the `POST /v1/transfers` endpoint.
**To finalize the deposit transfer:**
1. Use the POST request below to the `/v1/transfers` endpoint.
2. Include the `quote_id` obtained from Step 1.
3. Replace `{customer_id}` with the customer ID.
4. Replace `YOUR_BASE_URL` and `YOUR_SECRET_KEY` with your actual details.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'X-BU-PROFILE-ID: {customer_id}' \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8"
}'
```
**Sample Response with Generated Temporary Account Number:**
A successful response will return a Transfer object. The generated temporary bank account number and other recipient details will be located within the `data.pay_in.recipient_details` object of this response.
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_LJB2GQb55Cs98LbpqgRMx",
"profile_id": "CUS_BqpKZiPXPo3Vz",
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "10000",
"target_amount": "9900",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2025-02-21T10:46:56.232278869Z",
"recipient_details": {
"account_name": "Payaza(Business 1 Business)",
"account_number": "7000384620",
"bank_name": "78 FINANCE COMPANY LIMITED",
"email": "dickson@busha.co"
},
"type": "temporary_bank_account"
},
"status": "pending",
"created_at": "2025-02-21T10:16:54.40130914Z",
"updated_at": "2025-02-21T10:16:54.401309215Z"
}
}
```
Once you have the temporary bank account details, your application should display these to the customer, along with clear instructions to make the bank transfer. After the customer initiates the transfer, you'll need to monitor its status to confirm when the funds have been successfully deposited into your Busha balance.
**To monitor deposit status:**
* **Webhooks (Recommended):** Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes. This is the most efficient method for real-time updates.
* Refer to the How to Set Up Webhook Guide for detailed instructions
* **Polling (Less Recommended):** Periodically GET the transfer status using the transfer `id` (`TRF_LJB2GQb55Cs98LbpqgRMx` in the example). While possible, this is less efficient and can lead to rate limiting if done too frequently.
**Expected Transfer Statuses:**
* `pending`: Transfer initiated, awaiting user bank transfer.
* `completed`: Funds have been successfully received and credited to your Busha balance.
* `failed`: The deposit failed (e.g., transfer not received within timeframe, invalid details)
* `reversed`: The deposit was processed but later reversed.
## Troubleshooting Common Fiat Deposit Issues
**"Quote expired" during transfer finalization:** Always create a fresh quote immediately before attempting to finalize the transfer.
**Deposit not reflecting:** Check the transfer status via API/webhooks. If still `pending` after an extended period, contact Busha support with the `TRF_` ID.
**Temporary account expires:** Ensure the user makes the transfer before the `pay_in.expires_at` time shown in the transfer response. If expired, you may need to initiate a new deposit flow.
## What's Next?
Now that you know how to process fiat deposits, consider:
* [How to Process Crypto Deposits Guide](/guides/deposits/process-crypto-deposits)
* [How to Process Payouts Guide](/guides/payouts/process-payouts)
* Exploring all relevant API endpoints: [Quotes API Reference](/api-reference/quotes/list-quotes), [Transfers API Reference](/api-reference/transfers/list-transfers)
# Verify Customer Identity
Source: https://docs.busha.io/guides/customers/verify-identity
Implement KYC verification for customers. Collect documents and verify identity information.
This guide provides a technical walkthrough on programmatically verifying a customer account using the Busha API.
**What You'll Achieve:**
1. Update customer profile with KYC/KYB documents.
2. Successfully verify your customer identity.
3. Monitor verification status changes.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of **API Environments** (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
* A customer account created (see [Create Individual Customer](/guides/customers/create-individual) or [Create Business Customer](/guides/customers/create-business)).
## Verifying Customer Identity (KYC/KYB)
Skip this step if verification documents were attached when creating the
customer.
The core requirement for verifying a customer is the completed upload of identification documents.
Files uploaded for KYC/KYB must be in Base64 format and have a file size less than 4MB.
**Individual customer**
For individual customers, you must provide ONE of the following combinations in the `identifying_information` array:
**Option 1: Passport + Selfie**
```json theme={null}
"identifying_information": [
{
"type": "passport",
"number": "A12345678",
"country": "NG",
"image_front": "{{base64 encoded passport image}}"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
```
**Option 2: National ID + Selfie**
```json theme={null}
"identifying_information": [
{
"type": "national-id",
"number": "12345678901",
"country": "NG"
},
{
"type": "selfie",
"image_front": "{{base64 encoded selfie image}}",
"number": "",
"country": "NG"
}
]
```
Country
Documents Required
Nigeria
NIN number and selfie image
National passport and selfie image
Driver's license and selfie image
Kenya
National ID and selfie image
To update an individual customer with their verification documents:
1. Open your terminal or command prompt.
2. Use the `PUT` request below to the `/v1/customers/{customer_id}` endpoint.
3. Replace `{customer_id}` with the customer ID.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
5. Replace the values in the `identifying_information` array with the customer documents.
**Example with Passport + Selfie:**
```shell theme={null}
$ curl -i -X PUT https://YOUR_BASE_URL/v1/customers/{customer_id} \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@gmail.com",
"first_name": "John",
"last_name": "Doe",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "15-06-1990",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "10 Allen Avenue",
"postal_code": "100001"
},
"identifying_information": [
{
"type": "passport",
"number": "A12345678",
"country": "NG",
"image_front": "{{base64 string}}"
},
{
"type": "selfie",
"image_front": "{{base64 string}}",
"number": "",
"country": "NG"
}
]
}'
```
**Example with National ID + Selfie:**
```shell theme={null}
$ curl -i -X PUT https://YOUR_BASE_URL/v1/customers/{customer_id} \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@gmail.com",
"first_name": "John",
"last_name": "Doe",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "15-06-1990",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "10 Allen Avenue",
"postal_code": "100001"
},
"identifying_information": [
{
"type": "national-id",
"number": "12345678901",
"country": "NG"
},
{
"type": "selfie",
"image_front": "{{base64 string}}",
"number": "",
"country": "NG"
}
]
}'
```
## Verifying Individual Customers with a KYC Link
As an alternative, you can generate a hosted verification link and let the customer complete their own KYC directly.
Call the KYC link endpoint for the customer:
```bash theme={null}
curl -X POST "https://api.busha.io/v1/customers/CUS_xxx/kyc-link" \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json"
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "KYC link generated successfully",
"data": {
"url": "https://in.sumsub.com/websdk/p/sbx_j0t47nDxjmWDw503"
}
}
```
Send the returned `url` to your customer. They complete identity verification directly through this hosted flow.
Once your customer submits their information, their status updates the same way as document-based verification, moving from `inactive` to `in_review`, then to `active` or `rejected`.
This is only available for individual customers, not business customers.
**Business customer**
For business customers, the KYB documents and sections required are:
**Documents:**
* Certificate of Incorporation
* Corporate registry extract
* Memorandum of Association articles (memart)
* Corporate structure chart
* Board resolution
* Anti-money laundering policy
* Regulatory licenses
* Proof of wealth
* Proof of address
**Required Sections:**
* **Business Owners** - Directors and beneficial owners information
* **Business Transaction** - Expected transaction patterns and volumes
* **Business Registration** - Legal and regulatory details
To update a business customer with complete KYB information:
1. Open your terminal or command prompt.
2. Use the `PUT` request below to the `/v1/customers/{customer_id}` endpoint.
3. Replace `{customer_id}` with the customer ID.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
5. Include all required sections and documents.
```shell theme={null}
$ curl -i -X PUT https://YOUR_BASE_URL/v1/customers/{customer_id} \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "business@gmail.com",
"has_accepted_terms": true,
"type": "business",
"country_id": "NG",
"phone": "+234 8012345678",
"business_name": "ABC Corporation",
"business_industry": "BIN_C4UvTYR5V8jsOx5LmwQ",
"business_incorporation_date": "2015-06-15",
"documents": [
{
"purposes": ["certificate_of_incorporation"],
"file": "{{base64 string}}"
}
],
"business_owners": [
{
"first_name": "John",
"last_name": "Owner",
"role": ["director"],
"percentage_ownership": 100,
"is_pep": false,
"nationality": "NG",
"bvn": "12345678901"
}
],
"business_transaction": {
"purpose": "international trade",
"monthly_transaction_value": "above_1m_usd",
"monthly_transaction_count": "100_to_200",
"client_transaction_status": "self-owned",
"api_access_needed": true,
"api_integration_url": "https://yourbusiness.com"
},
"business_registration": {
"business_type": "type_registered_company",
"business_structure": "limited_liability_company",
"business_regulation_status": "regulated",
"registration_number": "RC1234567",
"tax_identification_number": "TIN1234567",
"corporate_group_status": "standalone_company",
"exchange_listing_status": "not_listed_on_exchange",
"license_number": "LIC123456"
}
}'
```
After uploading all required documents and information, call the verify endpoint to submit the customer for verification.
To verify the customer:
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/customers/{customer_id}/verify` endpoint.
3. Replace `{customer_id}` with the customer ID.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR_SECRET_KEY}` with your actual key.
```shell theme={null}
$ curl -i -X POST "https://YOUR_BASE_URL/v1/customers/{customer_id}/verify" \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}'
```
**Expected Response**
A successful response indicates the verification request has been submitted:
```json theme={null}
{
"status": "success",
"message": "Customer verified successfully"
}
```
After calling the verify endpoint, the customer status will change from `inactive` to `in_review`. You'll receive webhook notifications as the verification progresses.
Monitor the customer's verification status by retrieving their details:
```shell theme={null}
$ curl -i -X GET "https://YOUR_BASE_URL/v1/customers/{customer_id}" \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}'
```
**Customer Status Values:**
* `inactive` - Customer created but not yet verified
* `in_review` - Verification documents submitted and under review
* `active` - Customer verified and can perform transactions
* `rejected` - Verification failed (check rejection reason)
**Example Response:**
```json theme={null}
{
"status": "success",
"message": "Fetched customer successfully",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"email": "customer@gmail.com",
"first_name": "John",
"last_name": "Doe",
"type": "individual",
"status": "in_review",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T09:26:34.537881Z"
}
}
```
Set up webhooks to receive real-time notifications about verification status changes. See [Webhook Events](/guides/webhooks/webhook-events) for available customer verification events:
* `customer.verification.in_review` - Verification submitted
* `customer.verification.active` - Verification approved
* `customer.verification.rejected` - Verification failed
* `customer.verification.inactive` - Verification reverted
**Example Webhook Payload:**
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.verification.in_review",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "in_review",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z"
}
}
```
Learn how to set up webhooks in the [Webhooks Guide](/guides/webhooks/setup).
## Common Verification Errors
**Individual Customers:**
```json theme={null}
{
"error": {
"name": "profile_kyc_verification",
"message": "KYC document does not contain a selfie image"
}
}
```
**Solution:** Ensure the `identifying_information` array includes a selfie object with `type: "selfie"` and `image_front` containing a base64 encoded selfie image.
**Business Customers:**
```json theme={null}
{
"error": {
"name": "missing_section",
"message": "Owners section must be completed before final submission"
}
}
```
**Solution:** Add the `business_owners` array with at least one owner/director.
```json theme={null}
{
"error": {
"name": "missing_section",
"message": "Transaction section must be completed before final submission"
}
}
```
**Solution:** Add the `business_transaction` object with transaction details.
## Troubleshooting
* **`400 Bad Request / 422 Unprocessable Entity`:** Review your request body to ensure all required fields are present and correctly formatted.
* **`401 Unauthorized`:** Verify that your Secret API Key is correct and included in the header.
* **`missing_section` errors:** For business customers, ensure all three sections (owners, transaction, registration) are complete before verification.
* **`profile_kyc_verification` errors:** For individual customers, ensure all required documents (ID images and selfie image) are uploaded in the `identifying_information` array.
## What's Next?
Now that you can programmatically verify customers, you can proceed to perform transactions on their behalf:
* [How to Initiate Transactions on Behalf of a Customer](/guides/customers/transactions-on-behalf): Understand how to use the `customer_id` to perform operations for your customers.
* [Webhook Events](/guides/webhooks/webhook-events): Learn about all customer verification webhook events.
* [Monitor Verification Status](/guides/customers/check-status): Track customer verification progress.
# Process Crypto Deposits
Source: https://docs.busha.io/guides/deposits/process-crypto-deposits
Generate deposit addresses for cryptocurrency. Accept BTC, USDT, ETH, and more.
This guide explains how to programmatically facilitate cryptocurrency deposits into your Busha Business crypto balances (e.g., BTC, ETH, USDT). Crypto deposits, like fiat deposits, rely on Quotes to generate specific deposit instructions, but with a focus on crypto wallet addresses and networks.
**What You'll Achieve:**
* Understand the specific quote requirements for crypto deposits.
* Generate a deposit quote that provisions a crypto wallet address.
* Finalize the deposit transfer to obtain the unique deposit address.
* Learn how to instruct your users on making a crypto transfer.
* Monitor the status of crypto deposits.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Making Your First Request Guide](../getting-started/make-first-request)).
* A conceptual understanding of Quotes (from the [Understanding Quotes Explainer](../../overview/quotes))
* Familiarity with creating basic quotes (from the [Creating A Quote Guide](../quotes/create-first-quote)).
For deposit requests involving a customer, the `X-BU-PROFILE-ID` field should
be included in the request header, and its value should be set to the customer
ID for whom the request is performed on their behalf.
## Process Crypto Deposit
Crypto deposits are initiated by creating a Quote where both the `source_currency` and `target_currency` are the same cryptocurrency (e.g., BTC to BTC, USDT to USDT).
The critical distinction from fiat deposits is. the pay\_in object, which specifies `type: "address"` and the corresponding network for the cryptocurrency (e.g., "BTC" for Bitcoin, "ERC20" for Ethereum-based tokens like USDT). This informs Busha to prepare for generating a unique wallet address in that specific network upon transfer finalization.
**To get a crypto deposit quote:**
1. Open your terminal or command prompt.
2. Construct a POST request to the /v1/quotes endpoint.
3. Specify the `source_currency` and `target_currency` (both being the crypto you expect to receive), the source\_amount the user intends to deposit, and a `pay_in` object with `type: "address"` and `network`.
4. Replace `{address}` with the recipient address.
5. Replace `YOUR_BASE_URL` with your chosen environment's URL and `YOUR_SECRET_KEY` with your actual key.
```bash Create Quote theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"pay_in": {
"type": "address",
"network": "BTC",
"address": {address}
}
}'
```
**Expected Quoted Response:**
A successful response will return a standard Quote object. Note the `id` of the returned Quote (`QUO_nEnsWPZ8KErY598DCj9Pk` in the example data provided) , as you will need this ID for the next step. The pay\_in object in the quote response will mirror what you sent in the request.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_nEnsWPZ8KErY598DCj9Pk",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"target_amount": "0.0001",
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [],
"pay_in": {
"network": "BTC",
"type": "address"
},
"reference": "QUO_nEnsWPZ8KErY598DCj9Pk",
"status": "pending",
"created_at": "2025-02-24T14:52:33.221141634Z",
"updated_at": "2025-02-24T14:52:33.221141634Z"
}
}
```
After obtaining a valid Quote for a crypto deposit, you finalize the transfer. This crucial step is where Busha actually generates the unique crypto wallet address that your user will send funds to. The transfer object is initiated by using the `POST /v1/transfers` endpoint.
**To finalize the deposit transfer:**
1. Use the `POST` request below to the `/v1/transfers` endpoint.
2. Include the `quote_id` obtained from Step 1.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_KEY` with your actual details.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_nEnsWPZ8KErY598DCj9Pk"
}'
```
**Sample Response with Generated Crypto Wallet Address**
A successful response will return a Transfer object. This unique crypto wallet address will be located within the `data.pay_in.address` object of this response.
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_ZALYpZBvgHLLImcWY9CxI",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"quote_id": "QUO_nEnsWPZ8KErY598DCj9Pk",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"target_amount": "0.0001",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [],
"pay_in": {
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"expires_at": "2025-02-24T15:53:33.518656Z",
"network": "BTC",
"type": "address"
},
"status": "pending",
"created_at": "2025-02-24T14:53:32.411488796Z",
"updated_at": "2025-02-24T14:53:32.411488876Z"
}
}
```
Once you have the crypto wallet address and network details, your application should display these to the end-user, along with clear instructions to make the crypto transfer.
It is critical to instruct users to send the exact amount to the correct
address on the specified network.
After the user initiates the transfer, you'll need to monitor its status to confirm when the funds have been successfully deposited into your Busha balance.
**To monitor deposit status:**
* **Webhooks (Recommended)**: Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes (e.g., from `pending` to `completed` or `failed`). This is the most efficient method for real-time updates.
* **Polling (Less Recommended)**: Periodically GET the transfer status using the transfer id `TRF_ZALYpZBvgHLLImcWY9CxI` in the example). While it is possible, this is less efficient and can lead to rate limiting if done too frequently.
## Troubleshooting Common Fiat Deposit Issues
* **“Quote expired” during transfer finalization**: Always create a fresh quote immediately before attempting to finalize the transfer.
* **User sends wrong amount**: If the user sends an amount different from the `source_amount` specified in the quote, the deposit may fail or be delayed. Advise users to send the exact amount.
* **User sends to wrong address/network**: Funds sent to an incorrect address or on the wrong network may be unrecoverable. Emphasize the importance of accuracy.
* **Deposit not reflecting**: Check the transfer status via API/webhooks. If still pending after an extended period, contact Busha support with the `TRF_ `ID.
* **Address expires**: Ensure the user makes the transfer before the `pay_in.expires_at` time shown in the transfer response. If expired, you may need to initiate a new deposit flow.
## What's Next?
Now that you know how to process fiat deposits, consider:
* [Processing Fiat Deposits](./process-fiat-deposits).
* [Processing Payouts](../payouts/process-payouts)
* Exploring all relevant API endpoints: [Quotes API Reference](../../api-reference/quotes/create-a-new-quote), [Transfers API Reference](../../api-reference/transfers/create-transfer).
# Process Fiat Deposits
Source: https://docs.busha.io/guides/deposits/process-fiat-deposits
Accept NGN and KES deposits using temporary bank accounts.
This guide will walk you through the process of programmatically accepting fiat currency deposits (e.g., NGN, KES) into your Busha Business fiat balances. Fiat deposits are typically facilitated through the generation of temporary bank accounts.
**What You'll Achieve:**
* Understand the specific quote requirements for fiat deposits.
* Generate a deposit quote that provisions a temporary bank account.
* Finalize the deposit transfer to obtain the temporary bank account details.
* Learn how to instruct your users to make the deposit.
* Monitor the status of fiat deposits.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
* A conceptual understanding of Quotes (from the [Understanding Quotes Explainer](/overview/quotes)).
* Familiarity with creating basic quotes (from the [How to Create Your First Quote Guide](/guides/quotes/create-first-quote)).
For deposit requests involving a customer, the X-BU-PROFILE-ID field should be
included in the request header, and its value should be set to the customer ID
for whom the request is performed on their behalf.
## How to Process Fiat Deposits
Fiat deposits are initiated by creating a Quote, where the `source_currency` and `target_currency` are the same fiat currency (e.g., NGN to NGN). The key here is the `pay_in` object, which specifies that you intend to use a `temporary_bank_account` for the deposit. This informs Busha to prepare for generating such an account upon transfer finalization.
**To get a fiat deposit quote:**
1. Open your terminal or command prompt.
2. Construct a POST request to the /v1/quotes endpoint.
3. Specify the `source_currency` and `target_currency` (both being the fiat currency you expect to receive), the `source_amount` the user intends to deposit, and a `pay_in` object with type: `"temporary_bank_account"`.
4. Replace `YOUR_BASE_URL` with your chosen environment's URL and `YOUR_SECRET_TOKEN` with your actual key.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "10000",
"pay_in": {
"type": "temporary_bank_account"
}
}'
```
A successful response will return a standard Quote object, similar to what you've seen before. Note the `id` of the returned Quote (e.g., `QUO_vxcF2svmjMbxDp4T5dcD8` ), as you will need this ID for the next step. The `pay_in` object in the quote response will mirror what you sent in the request.
After obtaining a valid Quote for a fiat deposit, you finalize the transfer. This crucial step is where Busha generates the temporary bank account details that your user will transfer funds into. The transfer object is initiated using the `POST /v1/transfers` endpoint.
**To finalize the deposit transfer:**
1. Use the POST request below to the `/v1/transfers` endpoint.
2. Include the quote\_id obtained from Step 1.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_KEY` with your actual details.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8"
}'
```
**Sample Response with Generated Temporary Account Number:**
A successful response will return a Transfer object. The generated temporary bank account number and other recipient details will be located within the `data.pay_in.recipient_details` object of this response.
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_LJB2GQb55Cs98LbpqgRMx",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"quote_id": "QUO_vxcF2svmjMbxDp4T5dcD8",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "10000",
"target_amount": "9900",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "payment gateway fee",
"type": "FIXED"
}
],
"pay_in": {
"expires_at": "2025-02-21T10:46:56.232278869Z",
"recipient_details": {
"account_name": "Payaza(Business 1 Business)",
"account_number": "7000384620",
"bank_name": "78 FINANCE COMPANY LIMITED",
"email": "dickson@busha.co"
},
"type": "temporary_bank_account"
},
"status": "pending",
"created_at": "2025-02-21T10:16:54.40130914Z",
"updated_at": "2025-02-21T10:16:54.401309215Z"
}
}
```
Once you have the temporary bank account details, your application should display these to the end user, along with clear instructions to make the bank transfer. After the user initiates the transfer, you'll need to monitor its status to confirm when the funds have been successfully deposited into your Busha balance.
**To monitor deposit status:**
* **Webhooks (Recommended)**: Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes. This is the most efficient method for real-time updates.
* Refer to the [Setting Up Webhook Guide](../webhooks/setup) for detailed instructions.
* **Polling (Less Recommended)**: Periodically GET the transfer status using the transfer id (`TRF_LJB2GQb55Cs98LbpqgRMx` in the example). While possible, this is less efficient and can lead to rate limiting if done too frequently.
**Expected Transfer Statutes:**
* `pending`: Transfer initiated, awaiting user bank transfer.
* `processing`: This means the funds has been received, and is being handled.
* `funds_received`: Funds have been successfully received and credited to your Busha balance.
* `cancelled`: the transfer has been cancelled, and will not continue.
## Troubleshooting Common Fiat Deposit Issues
* **“Quote expired”** during transfer finalization: Always create a fresh quote immediately before attempting to finalize the transfer.
* **Deposit not reflecting**: Check the transfer status via API/webhooks. If still pending after an extended period, contact Busha support with the `TRF_` ID.
* **Temporary account expires**: Ensure the user makes the transfer before the pay\_in.expires\_at time shown in the transfer response. If expired, you may need to initiate a new deposit flow.
## What's Next?
Now that you know how to process fiat deposits, consider:
* [Processing Crypto Deposits](../deposits/process-crypto-deposits)
* [Processing Payouts](../payouts/process-payouts)
* Exploring all relevant API endpoints: [Quotes API Reference](../../api-reference/quotes/create-a-new-quote), [Transfers API Reference](../../api-reference/transfers/create-transfer).
# Process Deposits with Quote Currency
Source: https://docs.busha.io/guides/deposits/process-with-quote-currency
Process deposits using quote currency pairs. Convert funds during the deposit flow.
Only fiat currencies are supported for quote\_currency
This guide explains how to leverage Busha's Quotes API to process a quote using the `quote_currency` and `quote_amount` fields, allowing for transactions where the original value is denominated in a different FIAT currency than the source and target cryptocurrencies.
**What You'll Achieve:**
* Understand the specific parameters for this type of transaction.
* Generate a deposit quote that provisions a crypto pay in address
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Making Your First Request Guide](../getting-started/make-first-request)).
* A conceptual understanding of [Quotes](../../overview/quotes).
* Familiarity with creating basic quotes (from the [Creating A Quote Guide](../quotes/create-first-quote)).
For deposit requests involving a customer, the `X-BU-PROFILE-ID` field should
be included in the request header, and its value should be set to the customer
ID for whom the request is performed on their behalf.
## Get a Quote for the Deposit
A deposit is initiated by creating a Quote. In this guide, we're going to define the original currency for which the quote is being prepared which is fiat using the `quote_currency` field, as well as the amount of the `quote_currency` to be transacted.
This is useful for scenarios where a business wants a customer to pay for
services in a currency of their choice while still maintaining the original
price of the service regardless of the payment currency.
**To get a deposit quote:**
1. Identify the `quote_currency` and `quote_amount`:
* The `quote_currency` is the original currency for which the quote is being prepared (e.g., NGN, KES).
* The `quote_amount` is the amount of the `quote_currency` to be transacted (e.g., 50000).
2. Specify `source_currency` and `target_currency`:
* The `source_currency` is the cryptocurrency the user will use to pay (e.g., USDT).
* The `target_currency` is the cryptocurrency you want to receive and store (e.g., USDT).
3. Define the `pay_in` object:
* Set type to "address" as the medium of payment is a cryptocurrency address.
* Specify the network for the chosen `source_currency` (e.g., "TRX" for USDT).
4. Set the `pay_out` object:
* Set type to "balance" as the destination of the received funds is your Busha balance.
**Example quote object:**
```json theme={null}
{
"quote_currency": "NGN", // Original fiat currency of the value
"quote_amount": "50000", // Amount in the quote_currency
"source_currency": "USDT", // Currency user wants to pay with
"target_currency": "USDT", // Currency to be received in balance
"pay_in": {
"type": "address", // Medium of payment
"network": "TRX" // Network of the said currency
},
"pay_out": {
"type": "balance" // Destination of the money paid in
}
}
```
With the quote object defined, send a `POST` request to the `/v1/quotes` endpoint:
```bash theme={null}
$ curl -i -X POST https://BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"quote_currency": "NGN",
"quote_amount": "50000",
"source_currency": "USDT",
"target_currency": "USDT",
"pay_in": {
"type": "address",
"network": "TRX"
},
"pay_out": {
"type": "balance"
}
}'
```
A successful response will return a standard Quote object, similar to what you've seen before.
1. Locate the "`data`" object within the response.
2. Note the `id` of the returned Quote.
3. Extract the value from the "`source_amount`" field. This value represents the exact amount of cryptocurrency (e.g., USDT) the use needs to pay, which is calculated internally by Busha based on the `quote_currency`, `quote_amount`, and the current exchange rate.
4. Note the "`target_amount`" field, which indicates the amount of cryptocurrency you will receive. In this specific scenario, `source_amount` and `target_amount` will be the same.
**Example Response Snippet:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
// ... other fields
"id": "QUO_vxnndjeneiviu84",
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "32.851512", // Amount of crypto the user needs to pay
"target_amount": "32.851512" // Amount of crypto you will receive
// ... other fields
}
}
```
## Finalize the Deposit Transfer
To initiate the transfer process and obtain the unique cryptocurrency address for the user payment:
1. Create a transfer via the `/v1/transfers` endpoint with the quote ID retrieved from the response.
2. The API response for creating a transfer will contain a "`pay_in`" object.
3. Within the "`pay_in`" object, retrieve the "`address`" field. This is the unique cryptocurrency address where the user should send their payment.
Note the "expires\_at" field, which indicates when the payment address will
expire. Ensure the user completes the transaction before this time.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_vxnndjeneiviu84"
}'
```
**Example Response Snippet:**
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_LJB2GQb55Cs98LbpqgRGx"
// other fields
"source_currency": "USDT",
"target_currency": "USDT",
"source_amount": "32.851512",
"target_amount": "32.851512",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USDT"
},
"fees": [],
"pay_in": {
"address": "TWcYEz1UjSre7LqvvPyKHQ7EQzQ9oQDzit", // The crypto address to send payment to
"expires_at": "2025-07-20T23:22:52.857352Z",
"network": "TRX",
"type": "address"
},
// ... other fields
}
}
```
## Monitoring Deposit Status
After the user has made the payment to the provided address, you can query the transfer status using the transfer ID.
**To monitor deposit status:**
* \*\* Webhooks (Recommended):\*\* Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes. This is the most efficient method for real-time updates.
* Refer to the [Setting Up Webhook Guide](../webhooks/setup) for detailed instructions.
* **Polling (Less Recommended)**: Periodically GET the transfer status using the transfer id (`TRF_LJB2GQb55Cs98LbpqgRGx` in the example). While possible, this is less efficient and can lead to rate limiting if done too frequently.
**Expected Transfer Statutes:**
* `pending` : Transfer initiated, awaiting user deposit.
* `funds_received`: Funds have been successfully received and credited to your Busha balance.
* `cancelled`: the transfer has been cancelled, and will not continue.
## Troubleshooting Common Fiat Deposit Issues
* **“Quote expired” during transfer finalization**: Always create a fresh quote immediately before attempting to finalize the transfer.
* **Deposit not reflecting**: Check the transfer status via API/webhooks. If still pending after an extended period, contact Busha support with the TRF\_ ID.
## What's Next?
Now that you know how to process deposits using `quote_currency` and `quote_amount`, consider:
* [Processing Fiat Deposits with Regular Quotes](./process-fiat-deposits).
* [Processing Crypto Deposits](./process-crypto-deposits)
* [Processing Payouts](../payouts/process-payouts)
* Exploring all relevant API endpoints: [Quotes API Reference](../../api-reference/quotes/create-a-new-quote), [Transfers API Reference](../../api-reference/transfers/create-transfer).
# Generate API Keys
Source: https://docs.busha.io/guides/getting-started/generate-api-key
Create and manage your Busha API keys.
API keys are credentials that allow applications to access and interact with the Busha API. They serve as unique identifiers and authenticators, ensuring that only authorized applications can perform specific actions. Busha utilizes two main types of API keys, each with distinct purposes and security considerations:
### Public API Key
This key is designed for use in client-side applications, such as your website's frontend or mobile app. Its primary purpose is to identify your application when interacting with public-facing API endpoints, like those used by our On-Ramp and Off-Ramp widgets. While it helps track usage and identify your application, it's not considered sensitive and can be exposed in public code without compromising your security.
### Secret API Key
In contrast, the Secret API Key is a highly sensitive credential strictly for server-side use. It grants your application full access to perform secure and privileged operations, such as creating transfers, managing recipients, or accessing confidential data. This key must be kept confidential and never exposed in client-side code, stored in version control, or shared publicly, as its compromise could lead to unauthorized access to your Busha account and funds.
## Prerequisites
Before you start, make sure you have:
* A Busha Business Account (from the [Quick Start Guide](/guides/getting-started/quick-start)).
## How to Generate API Keys
The first step to obtaining your API keys is to log in to your Busha Business Dashboard and navigate to the dedicated API key management area.
Log in to your Busha Business Dashboard:
* Open your web browser and go to the Busha Business login page (e.g., [https://app.busha.io/login](https://app.busha.io/login)).
* Enter your registered email address and password.
* Complete any multi-factor authentication (MFA) steps if prompted.
1. From your Busha Business dashboard, go to the side bar and click settings.
Dashboard with settings in focus
2. Click on **"Developer tools > API Tokens"**.
Developer tools in focus
3. Click on the **"Add New Token".**
Busha generates a public key for your account immediately you sign up.
Developer tools with Add New Token in focus
4. Name your token and select the permissions for the token.
Create an API token page
5. Enter your 6-digit code from your 2FA application
Security authentication page for token generation
6. A pop-up window will appear, displaying your newly generated API key.
Details of the API key created
**Attention!**
1. Immediately copy and securely store your API key. This key will only be displayed once for security reasons, but it can be regenerated at any time.
2. Do NOT commit your API key to Git, or use it in client-side code.
## What's Next?
Now that you have successfully obtained and understood your API keys, you're ready to proceed with integrating Busha's services into your application:
* [How to Integrate the On-Ramp Widget](/guides/widgets/integrate-on-ramp): Learn how to use your Public API key to enable fiat-to-crypto conversions on your platform.
* [How to Integrate the Off-Ramp Widget](/guides/widgets/integrate-off-ramp): Learn how to use your Public API key to enable crypto-to-fiat conversions on your platform.
* [Busha API Reference](/api-reference/introduction): Explore the full range of API endpoints and their functionalities that you can access with your Secret API Key.
# Choose Your Integration Path
Source: https://docs.busha.io/guides/getting-started/integration-paths
Pick the fastest Busha integration path: Payments API, Payments SDK, On/Off-ramp APIs, or Customer onboarding for B2B2C.
Not sure where to begin? Start with the path that matches what you're building.
## 1) Accept payments via API
Use server-to-server APIs when you want full control over your payment flow.
Start with [Create your first payment request](/guides/payment-requests/create-first-payment).
Confirm updates with [Retrieve payment request](/guides/payment-requests/retrieve-payment).
Subscribe to events using [Webhook setup](/guides/webhooks/setup) and [Webhook events](/guides/webhooks/webhook-events).
## 2) Accept payments via SDK / widgets
Use Busha-hosted UI components when you want faster frontend delivery.
* [Accept stablecoin payments with Payment Widget](/guides/accepting-stablecoin-payments/payment-widget)
* [Create shareable payment links](/guides/accepting-stablecoin-payments/payment-links)
* [Integrate on-ramp widget](/guides/widgets/integrate-on-ramp)
* [Integrate off-ramp widget](/guides/widgets/integrate-off-ramp)
## 3) Build on-ramp/off-ramp flows via API
Use quote + transfer APIs for programmable fiat/crypto conversion flows.
Begin with [Create your first quote](/guides/quotes/create-first-quote).
Follow [Process fiat deposits](/guides/deposits/process-fiat-deposits) or [Process crypto deposits](/guides/deposits/process-crypto-deposits).
Continue with [Process payouts](/guides/payouts/process-payouts) or [Process crypto payouts](/guides/payouts/process-crypto-payouts).
## 4) Onboard customers for B2B2C services
Use customer profiles and verification to support delegated services.
* [Create individual customer](/guides/customers/create-individual)
* [Create business customer](/guides/customers/create-business)
* [Verify customer identity](/guides/customers/verify-identity)
* [Transact on behalf of customers](/guides/customers/transactions-on-behalf)
## Recommended first run (10 minutes)
1. [Quick Start](/guides/getting-started/quick-start)
2. [Generate API key](/guides/getting-started/generate-api-key)
3. [Make your first request](/guides/getting-started/make-first-request)
4. Choose one integration path above and implement end-to-end.
# Making Your First Request
Source: https://docs.busha.io/guides/getting-started/make-first-request
Send your first request to the Busha API.
Welcome to the exciting part - sending your first API request to Busha! This tutorial will guide you through making a simple **GET** request to retrieve your account's wallet balances. Completing this will confirm your setup is correct and you're ready to integrate with Busha's services.
**What You'll Achieve:**
* Successfully sent an authenticated request to the Busha API.
* Retrieve your current wallet balances.
* Confirm your API keys are working correctly.
## Prerequisites
Before you start, make sure you have:
* A Busha Business Account (from the [Quick Start Guide](/guides/getting-started/quick-start)).
* Your Secret API Key copied and securely stored (from the Quick Start Guide).
## How to make your First Request
Busha provides different environments for testing and live operations. For this first request, we'll focus on your Sandbox environment if you're testing, or Production if your account is fully approved.
* Sandbox (Testing Environment): [`https://api.sandbox.busha.so`](https://api.sandbox.busha.so)
You can create a [sandbox account](./setup-sandbox) from the Sandbox business registration page using the same steps from the [Quick Start](./quick-start) guide. Sandbox personal accounts require 2FA, and businesses are automatically verified.
* Live (Production Environment): [`https://api.busha.co`](https://api.busha.co)
For your first successful test, we recommend using the Sandbox environment if your account isn't fully verified for production yet. This ensures you can test without affecting live data.
All requests to the Busha API require authentication using your Secret API Key. You'll include this key in the Authorization header of your requests using a Bearer token.
The `Authorization: Bearer {your_secret_api_key}` header tells the Busha API who is making the request, ensuring it's coming from your verified business account.
Keep your Secret API Key handy. You'll replace in the upcoming command, with your actual key.
Now, let's retrieve your wallet balances using a curl command. This is a basic GET request, meaning we are simply asking for information from the API.
To make your first GET request:
1. Open your terminal or command prompt
2. Copy the curl command below
```bash theme={null}
$ curl -X GET "YOUR_BASE_URL/v1/balances" \
-H "Authorization: Bearer {YOUR_SECRET_API_KEY}" \
-H "Content-Type: application/json"
```
Replace YOUR\_BASE\_URL with your desired API environment and YOUR\_SECRET\_API\_KEY with your secret API key.
After executing the curl command, the Busha API will send back a response.
A successful response will return a JSON object containing an array of your wallet balances. It should look something like this (actual values will vary):
```json theme={null}
{
"status": "success",
"message": "Fetched balances successfully",
"data": [
{
"id": "96da4899-ff99-4821-88df-5182b8d37300",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "GHS",
"name": "Cedi",
"type": "fiat",
"available": {
"amount": "0",
"currency": "GHS"
},
"pending": {
"amount": "0",
"currency": "GHS"
},
"total": {
"amount": "0",
"currency": "GHS"
}
},
{
"id": "05320e5e-a8ff-48e4-ac0b-23f7b1aa14d7",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "KES",
"name": "Shilling",
"type": "fiat",
"available": {
"amount": "0",
"currency": "KES"
},
"pending": {
"amount": "0",
"currency": "KES"
},
"total": {
"amount": "0",
"currency": "KES"
}
},
{
"id": "960ab09d-cd55-4118-8b6e-c12b340efec3",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "NGN",
"name": "Naira",
"type": "fiat",
"available": {
"amount": "0",
"currency": "NGN"
},
"pending": {
"amount": "0",
"currency": "NGN"
},
"total": {
"amount": "0",
"currency": "NGN"
}
},
{
"id": "1ebeabb4-6e4f-449f-8c0f-18a9c9d9187a",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USD",
"name": "US Dollar",
"type": "fiat",
"available": {
"amount": "0",
"currency": "USD"
},
"pending": {
"amount": "0",
"currency": "USD"
},
"total": {
"amount": "0",
"currency": "USD"
}
},
{
"id": "bc1dfeae-055e-4d4e-a583-0c8030e5a1cd",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "BTC",
"name": "Bitcoin",
"type": "crypto",
"available": {
"amount": "0",
"currency": "BTC"
},
"pending": {
"amount": "0",
"currency": "BTC"
},
"total": {
"amount": "0",
"currency": "BTC"
}
},
{
"id": "b8dbf5e4-4d1f-4489-81fe-2a5e1e9816e1",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "ETH",
"name": "Ethereum",
"type": "crypto",
"available": {
"amount": "0",
"currency": "ETH"
},
"pending": {
"amount": "0",
"currency": "ETH"
},
"total": {
"amount": "0",
"currency": "ETH"
}
},
{
"id": "ec5744b6-ab06-4180-b354-e672b9a5f30a",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USDC",
"name": "USD Coin",
"type": "crypto",
"available": {
"amount": "0",
"currency": "USDC"
},
"pending": {
"amount": "0",
"currency": "USDC"
},
"total": {
"amount": "0",
"currency": "USDC"
}
},
{
"id": "fb891621-0b15-45f5-9b81-ea3995cbf891",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"currency": "USDT",
"name": "USD Token",
"type": "crypto",
"available": {
"amount": "0",
"currency": "USDT"
},
"pending": {
"amount": "0",
"currency": "USDT"
},
"total": {
"amount": "0",
"currency": "USDT"
}
}
],
"pagination": {
"current_entries_size": 8
}
}
```
If you see a `"status": "success"` and data about your accounts, congratulations! You've successfully made your first request.
## Troubleshooting
* **Unauthorized request or 401 error:** Double-check that you replaced `{YOUR_SECRET_API_KEY}` with your actual Secret API Key, and ensure there are no extra spaces or characters.
* **Resource Not Found or 404 error:** Verify the base URL is correct (Sandbox vs. Live) and the endpoint path (`/v1/balances`) is accurate.
* **No response:** Check your internet connection and ensure curl is correctly installed and accessible in your terminal.
## What's Next?
Now that you've successfully made your first API request, you can:
* Explore more API functionalities and endpoints in the Sandbox Environment.
* Refer to the Busha API Reference for comprehensive details on all available endpoints, request bodies, and responses.
* Move on to more specific tasks by checking out our [How-to Guides](../).
# Quick Start
Source: https://docs.busha.io/guides/getting-started/quick-start
Get started with Busha API. Create your account, generate API keys, and make your first request.
Welcome to Busha! This tutorial will walk you through the essential steps to get your business account set up and obtain your API keys, so you can start integrating Busha's powerful financial services into your application.
By the end of this tutorial, you'll have successfully set up your Busha Business Account, submitted all necessary documents for verification, and generated your API keys.
Please note that full access for live transactions requires successful business verification and approval. This guide gets you ready to proceed with the verification process quickly.
## Setting up your Account
Let's begin by creating your dedicated business account.
1. Log in to your [Busha personal account](https://dash.busha.io).
2. Locate the Avatar dropdown menu at the top right corner of your dashboard.
3. Select Open a business account from the menu. Follow the prompts to initiate your business account creation.
User dashboard with Open a business account highlighted in the avatar dropdown menu
This is ideal if you prefer to keep your business operations entirely separate from your account.
1. Visit the [Busha Business registration](https://dash.busha.io/business/signup) page.
2. Follow the on-screen instructions to sign up for a new business account.
You will have successfully initiated the creation of your Busha Business Account and will be directed to your new business dashboard.
To unlock all of Busha's features and activate your account, you need to complete the [Know Your Business (KYB)](/overview/compliance) process.
1. On your Busha Business dashboard, click on the "**Verify Now**" button.
Business dashboard with a focus on Verify now
2. Carefully follow the instructions to **submit and upload [all required Know Your Business (KYB) documents](/overview/compliance#requirements-for-business-customers-kyb-know-your-business)**. This typically includes business registration, ownership structure, and other relevant company information.
You will receive confirmation that your documents have been submitted for review. Your account status will be updated to "Pending Verification". **We will notify you via email once your KYB is approved, which is required for live API access.**
Once your business account is approved, enabling 2FA is the next step to protect your account and API keys.
1. From your **Avatar Dropdown Menu**, click on your **Personal account**.
Business dashboard with a focus on Personal account
2. Click on Settings on the left sidebar, and go to the Security page.
Security page with security tab highlighted
3. Click on **Two Factor Authentication** and follow the on-screen prompt.
Security page with Two Factor Authentication in focus
4. Input the verification code sent to your registered email address.
Verify your identity to enable 2FA
5. Register your Busha account with an authenticator application like Google Authenticator and input the Time-based One Time Token (TOTP) from your authenticator application.
Activation key for authenticator application of choice
6. You're all set!
Success page : 2FA successfully enabled
2FA has been successfully enabled for your Busha account, adding an extra layer of security.
At this juncture, you are already familiar with the Busha dashboard. You'll create your unique API keys to interact with Busha's services.
1. From your Busha Business dashboard, go to the side bar and click settings.
Dashboard with settings in focus
2. Click on **"Developer tools > API Tokens"**.
Developer tools in focus
3. Click on the **"Add New Token"**.
Developer tools with Add New Token in focus
4. Name your token and select the permissions for the token.
Create an API token page
5. Enter your 6-digit code from your 2FA application
Security authentication page for token generation
6. A pop-up window will appear, displaying your newly generated API key.
Details of the API key created
**Attention!**
1. Immediately copy and securely store your API key. This key will only be displayed once for security reasons, but can be regenerated at will.
2. Do **NOT** commit your API key to Git, or use it in client-side code.
You have successfully generated a secret API key with full permissions. With this API key, you're ready to interact with Busha programmatically.
## Understanding Your API Keys
* Public Keys: These are safe to use in your front-end applications (e.g., directly from your website or mobile applications using Busha's SDKs). They are designed to initiate transactions on your behalf and cannot modify your account.
* Secret Keys: These must be kept strictly confidential and never committed to version control (like Git) or used in client-side code. They grant full access to your account's API functionalities. If you ever suspect that your secret key has been compromised, you can easily reset it from your dashboard
## What's Next?
Now that you have verified your Busha Business Account and API Keys, you're ready to Make Your First Request!
# Setting up a Sandbox
Source: https://docs.busha.io/guides/getting-started/setup-sandbox
Learn how to set up your sandbox environment for testing Busha integrations safely.
You've successfully made your first request to Busha! Now, it's time to unleash your development creativity in the Busha Sandbox environment fully. This dedicated testing ground allows you to build, test, and iterate on your integrations without affecting live data or incurring real costs.
**What You'll Achieve:**
1. Understand the purpose and benefits of the Sandbox.
2. Learn how to configure your requests for the Sandbox.
3. Explore and test various Busha API endpoints in a safe space.
## Why Use the Sandbox?
The Sandbox environment is your essential playground for:
* **Risk-Free Testing**: Experiment with different API calls, edge cases, and error handling without impacting real users or funds.
* **Rapid Iteration**: Develop and debug your application's integration quickly and efficiently.
* **Feature Exploration**: Explore Busha before going live.
* **Simulated Scenarios**: Mimic various user flows and transaction outcomes (e.g., successful deposits, failed payouts, specific error codes).
**Create Your Sandbox Account First**
Before you begin, you need a Busha Sandbox account to get your API keys.
**Create a sandbox account:** [https://sandbox.dash.busha.io/business/signup](https://sandbox.dash.busha.io/business/signup)
Follow the same signup steps from the [Quick Start](/guides/getting-started/quick-start) guide. Sandbox personal accounts require **2FA**, and business accounts are automatically verified.
Please note that you still need to go through the KYB submission flow first, you can use dummy data and documents for this, it only takes about 5 minutes.
## How to Setup your Sandbox
The primary difference between the Sandbox and the Production environment is the **base URL** used for API requests.
**To connect to the Sandbox**: Ensure your API calls target the following base URL:
[`https://api.sandbox.busha.so`](https://api.sandbox.busha.so)
**Example**
If your first request to production was [https://api.busha.co/v1/accounts](https://api.busha.co/v1/accounts), the equivalent Sandbox request would be [https://api.sandbox.busha.so/v1/accounts](https://api.sandbox.busha.so/v1/accounts).
The API key you generated in the Quick Start Guide is valid for the Sandbox environment.
To use your API keys in the Sandbox environment, continue to use your `Authorization: Bearer {your_secret_api_key}` header with the Secret API Key you obtained previously for all Sandbox requests.
With your environment configured, you can now start sending various requests to the Sandbox API. Think about the features you want to integrate into your application and try making the corresponding API calls.
Let's retrieve our Sandbox account balances:
```bash theme={null}
$ curl -X GET "https://api.sandbox.busha.so/v1/balances" \
-H "Authorization: Bearer {YOUR_SECRET_API_KEY}" \
-H "Content-Type: application/json"
```
**Expected Response**:
```json theme={null}
{
"status": "success",
"message": "message for success",
"pagination": {
"next_cursor": "MjAyNC0xMC0xNVQxMTowNTo1My45NTkxNDErMDE6MDA=",
"current_entries_size": 20,
"previous_cursor": "MjAyNC0xMC0xNVQxMDowNTo1My45NTIxQjE3MDE6MDA="
},
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "platform_123456",
"profile_id": "platform_123456",
"currency": "BTC",
"name": "Bitcoin",
"type": "crypto",
"pending": {
"amount": "100",
"currency": "BTC",
"fiat": {
"amount": "100",
"currency": "BTC"
}
},
"available": {
"amount": "100",
"currency": "BTC",
"fiat": {
"amount": "100",
"currency": "BTC"
}
},
"savings": {
"amount": "100",
"currency": "BTC",
"fiat": {
"amount": "100",
"currency": "BTC"
}
},
"investments": {
"amount": "100",
"currency": "BTC",
"fiat": {
"amount": "100",
"currency": "BTC"
}
},
"total": {
"amount": "100",
"currency": "BTC",
"fiat": {
"amount": "100",
"currency": "BTC"
}
}
}
]
}
```
## Funding Your Sandbox Account
Before you can test transfers, quotes, or payouts, your sandbox account needs a balance. Since Sandbox doesn't move real money, you can simulate a fiat deposit directly from the dashboard in a few clicks.
Once you've completed KYB and your business account is verified, go to your Sandbox dashboard. To fund your sandbox account with fiat, you can simulate a deposit by clicking on the deposit icon.
From the dropdown, click on **Deposit cash**.
Select your preferred currency.
Enter an amount and continue.
You'll be directed to the details screen. Click **I have made the transfer**, and your account will be credited.
You can now convert these funds to other fiat currencies or crypto via the API
or the dashboard for your testing.
## Important Sandbox Notes & Limitations
* **No Real Funds**: All transactions performed in the Sandbox are simulated. No actual money will move, and your real balances remain unaffected.
* **Test Data**: The Sandbox may contain predefined test accounts or mock data. Do not expect it to reflect your live production balances.
* **Rate Limits**: While generally more lenient than production, observe fair usage. Excessive requests might still be rate-limited.
* **Feature Parity**: The Sandbox aims for high feature parity with production, but some advanced or newly released features might not be immediately available or behave slightly differently. Always check the API reference for specific endpoint statuses.
* **Error Simulation**: The Sandbox is excellent for testing error handling. You can often trigger specific error responses by using certain invalid inputs. Consult the [Error Handling Reference](../../api-reference/introduction#error-handling) for details on how to simulate common errors for robust error handling in your application.
## What's Next?
Once you're confident with your integration in the sandbox and your application is performing as expected, you'll be ready to transition to the live Production Environment.
# Endpoints
Source: https://docs.busha.io/guides/oauth/endpoints
Full reference for all Busha OAuth2 protocol endpoints.
The OAuth2 surface is split into two hosts: protocol endpoints at the issuer (`login.busha.io`) and the resource API (`api.busha.io`). OAuth app management — creating apps, revealing secrets, editing redirect URIs — is dashboard-only at [app.busha.io](https://app.busha.io).
| Method | Endpoint | Purpose |
| ------ | ----------------------------------- | ----------------------------------------------------------- |
| `GET` | `/oauth2/auth` | Start an authorization request (browser redirect). |
| `POST` | `/oauth2/token` | Exchange a code for tokens, or refresh an existing session. |
| `POST` | `/oauth2/revoke` | Revoke an access or refresh token. |
| `GET` | `/.well-known/openid-configuration` | OIDC discovery document. |
| `GET` | `/.well-known/jwks.json` | Public keys for JWT signature verification. |
## `GET /oauth2/auth`
Browser redirect — this is where you send the user's browser to start authorization. Never call this server-to-server.
**Required query parameters:**
| Parameter | Value |
| ----------------------- | ------------------------------------------------------------------ |
| `response_type` | `code` |
| `client_id` | Your app's `client_id` |
| `redirect_uri` | Byte-identical to a registered URI |
| `scope` | Space-separated scope list |
| `state` | CSRF guard — at least 16 random bytes, bound to the user's session |
| `code_challenge` | `base64url(sha256(code_verifier))` |
| `code_challenge_method` | `S256` — `plain` is not accepted; missing challenges are rejected |
**Success:** Redirects to your callback with `?code=...&state=...`
**User cancelled:** Redirects with `?error=access_denied&state=...`
## `POST /oauth2/token`
Server-to-server. Authenticate with HTTP Basic using `client_id:client_secret`. Never call this from the browser.
### Authorization code → tokens
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=$AUTH_CODE" \
--data-urlencode "redirect_uri=https://yourapp.example.com/oauth2/callback" \
--data-urlencode "code_verifier=$CODE_VERIFIER"
```
### Refresh token → new pair
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "refresh_token=$REFRESH_TOKEN"
```
**Important details:**
* `id_token` is returned only when `openid` is in the granted scopes.
* `refresh_token` is returned only when `offline_access` is granted.
* `redirect_uri` must exactly match a registered URI.
* Authorization codes are **single-use** and expire in **10 minutes**.
* Token exchange is **not idempotent** — if your callback handler runs twice, the second call returns `invalid_grant`.
**Accepted grant types:** `authorization_code` (with PKCE-S256) and `refresh_token` only. Implicit, resource-owner password, and `client_credentials` are not supported.
## `POST /oauth2/revoke`
Revoke an access or refresh token. Call this when a user disconnects your integration.
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/revoke \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "token=$REFRESH_TOKEN" \
--data-urlencode "token_type_hint=refresh_token"
```
Returns `200` with an empty body regardless of whether the token was valid — this is intentional to avoid leaking token validity information.
Revoking a refresh token kills future refreshes immediately but does **not** invalidate a currently-issued access token. The access token continues to validate until `exp`.
## `GET /.well-known/openid-configuration`
The OIDC discovery document. Contains the canonical `issuer` string and the URLs of all protocol endpoints.
```bash theme={null}
curl https://login.busha.io/.well-known/openid-configuration
```
Read the `issuer` value from this document at startup and pin your JWT validation against it. Do not hardcode the issuer string.
## `GET /.well-known/jwks.json`
The public key set used to verify JWT signatures.
```bash theme={null}
curl https://login.busha.io/.well-known/jwks.json
```
Cache the response for \~5 minutes. Refetch when you encounter a `kid` in a JWT header that is not present in your cache.
# Errors
Source: https://docs.busha.io/guides/oauth/errors
Every OAuth2 and API error, what causes it, and how to fix it.
## Error envelopes
Errors come in two shapes depending on which surface returned them.
**OAuth2 protocol endpoints** (`/oauth2/auth`, `/oauth2/token`, `/oauth2/revoke`) return RFC 6749 §5.2 shape:
```json theme={null}
{
"error": "invalid_grant",
"error_description": "code has already been used"
}
```
**Busha resource API** errors return:
```json theme={null}
{
"status": "error",
"message": "Insufficient scope",
"error": {
"name": "insufficient_scope",
"message": "this endpoint requires balances:read"
}
}
```
`error_description` is human-readable diagnostic text — do not surface it verbatim to end users.
## OAuth2 errors
| Error | Surface | Cause | Fix |
| ----------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_request` | All OAuth2 endpoints | Malformed request — missing parameter, bad encoding, wrong content type. | Validate your request shape against the [Endpoints reference](./endpoints). |
| `invalid_client` | `/oauth2/token` | Wrong `client_id`, wrong `client_secret`, or wrong authentication method. | Use HTTP Basic auth with URL-encoded `client_id:client_secret`. |
| `invalid_grant` | `/oauth2/token` | Code reused, code expired (10 min window), PKCE mismatch, or refresh token already rotated (family revoked). | For codes: make your callback handler idempotent — deduplicate on `state` or the code itself. For refresh tokens: treat as a hard disconnect and prompt re-authorization. |
| `invalid_scope` | `/oauth2/auth` | Scope not in the [catalog](./scopes), or not in your `approved_scopes`. | Compare your requested scopes against the catalog and your approved set on the dashboard. |
| `unauthorized_client` | `/oauth2/auth` | Client status is `pending`, `rejected`, or `suspended`. | Check your app status on the dashboard. |
| `access_denied` | Callback (`/callback`) | User clicked Cancel on the consent screen. | Render a "continue without connecting" path in your UI. |
| `redirect_uri does not match` | OAuth2 endpoints | `redirect_uri` is not byte-identical to a registered URI. | Compare bytes against the dashboard value. Check trailing slash, scheme, port, path casing. |
## Resource API errors
| HTTP status | Error name | Cause | Fix |
| ------------------ | -------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `401 Unauthorized` | — | Access token expired, revoked, or signature verification failed. | Refresh the access token. Force a JWKS refetch if the `kid` is unknown. |
| `403 Forbidden` | `insufficient_scope` | The token does not include the scope required by this endpoint. | Inspect the `scp` claim in the access token. Re-authorize with the broader scope set. |
## Common gotchas
**`invalid_grant` on code exchange**
Token exchange is not idempotent — authorization codes are single-use. If your callback handler runs twice (user double-clicks, browser retry), the second exchange returns `invalid_grant`. Deduplicate on the `state` value or the `code` itself in your callback handler.
**`invalid_grant` on refresh**
A refresh token can only be used once. If you replay a previously-used refresh token, Busha revokes the entire token family — all tokens for that user are immediately invalidated. Handle any `invalid_grant` on a refresh as a hard disconnect and send the user through the authorization flow again.
**Access token still works after refresh token revocation**
Revoking a refresh token prevents new tokens from being minted, but does not invalidate an already-issued access token. JWTs self-expire at `exp` (\~1 hour). This is by design. If you need instant invalidation, layer a server-side allowlist on critical endpoints.
**`openid` scope not shown on consent screen**
`openid` and `offline_access` are protocol scopes that Busha hides from the consent UI. If you received an `id_token` and `refresh_token`, they were granted successfully.
# Get Access
Source: https://docs.busha.io/guides/oauth/get-access
Register your OAuth2 app, obtain your client credentials, and decide whether to start in sandbox or production.
## Before you begin
OAuth2 app registration sits inside your Busha business account. Make sure you have:
* A **Busha business account** with completed KYB (Know Your Business) verification.
* The **scopes** your integration needs. Review the [Scopes reference](./scopes) before registering — you request scopes at registration time, and an admin approves the bundle.
If you haven't set up a business account yet, follow the [Quick Start guide](../getting-started/quick-start) first.
***
## Register your OAuth2 app
Sign in to your Busha business account at [app.busha.io](https://app.busha.io). In the sidebar, go to **Settings → Developer Tools → OAuth Apps** and click **Create App**.
Provide a name, homepage URL, and one or more **redirect URIs**. Select the [scopes](./scopes) your integration requires.
Register the **exact** redirect URI your app will send in the authorization request. Busha compares it byte-for-byte — a trailing slash, different casing, or a missing port makes it a different URI and the request will be rejected. HTTPS is required for all redirect URIs unless the host is `localhost`.
Submit. Your app lands in **pending** status.
Busha admin reviews and approves your app. You'll be notified when the status changes. Approval grants your app the full set of scopes you requested — `approved_scopes = requested_scopes`.
If your app shows `pending`, `rejected`, or `suspended` in the dashboard, authorization requests will fail with `unauthorized_client`.
Once approved, open the app page and click **Reveal Client Secret**. The secret is shown **exactly once** — copy it into your secret manager immediately.
Your credentials are:
| Credential | Format | Where to find it |
| --------------- | ---------------------------------- | ------------------------------------------ |
| `client_id` | `busha-oauth2-{uuid}-{live\|test}` | App page, always visible |
| `client_secret` | Opaque string | Click **Reveal Client Secret** (once only) |
Use **Rotate Secret** on the same page if your secret is ever compromised.
`client_secret` belongs in your backend — never in a mobile app, single-page app, browser extension, or anything shipped to users. Store it in a secret manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager).
***
## Sandbox vs production
Sandbox and production are fully isolated — they have separate URLs, separate OAuth2 clients, separate users, and separate tokens. Nothing crosses between them.
| | Sandbox | Production |
| ----------------------- | -------------------------------------------- | ---------------------------------------- |
| **Purpose** | Test your integration safely | Live customer traffic |
| **Approval turnaround** | Lighter-touch (ask your integration manager) | Standard KYB review |
| **Credentials** | Separate `client_id` and `client_secret` | Separate `client_id` and `client_secret` |
| **API host** | `api.sandbox.busha.so` | `api.busha.io` |
| **OAuth2 issuer** | `login.sandbox.busha.io` | `login.busha.io` |
Register a separate OAuth2 app for each environment. Never reuse production credentials in sandbox — the data sets are isolated and mixing credentials muddies your testing.
To get sandbox access, complete partner onboarding at the sandbox host. Talk to your integration manager about approval turnaround.
***
## What's next
You have your `client_id` and `client_secret`. Now make your first authorized API call:
Walk through the full authorization-code flow and call `GET /v1/balances` on behalf of a real user.
# Busha OAuth2
Source: https://docs.busha.io/guides/oauth/overview
Let your users connect their Busha accounts to your product — securely, without ever sharing their password.
## What is Busha OAuth2?
Busha OAuth2 is a delegated-authorization protocol that lets your application act on a Busha customer's behalf. After the customer signs in to Busha and consents to the permissions your app requests, your backend receives a short-lived access token. You attach that token to Busha API calls and interact with the customer's account — reading balances, initiating transfers, generating addresses — without ever seeing their password or holding their credentials.
The protocol is standard **OAuth2 authorization-code grant with PKCE-S256**, plus **OpenID Connect** for user identity. The endpoints are RFC-conformant and work with any compliant OAuth2 client library.
If you only need to call Busha as your own business (no end-user involved), use a **partner API key** instead. OAuth2 is purpose-built for cases where a real Busha customer is granting your app access to their account.
## Why OAuth2?
When you build a product on top of Busha — a wallet aggregator, an accounting integration, a treasury dashboard — your users already have Busha accounts with funds in them. OAuth2 gives you a safe, auditable way to interact with those accounts:
* **No password sharing.** Your app never sees the user's Busha credentials.
* **Scoped permissions.** You request only what your integration needs. The customer sees exactly what they're granting.
* **Revocable access.** The customer can disconnect your app at any time from their Busha dashboard. You can also revoke programmatically.
* **Short-lived tokens.** Access tokens expire in \~1 hour. Refresh tokens rotate on every use. A leaked token has a bounded blast radius.
* **Industry-standard.** Any OAuth2-compliant library handles the protocol plumbing so you ship faster.
## What you can build
Read balances and transaction history across a user's Busha wallets. Use `balances:read` and `transactions:read`.
Read existing deposit addresses or generate new ones on the user's behalf. Add `addresses:read` and `addresses:write`.
Initiate transfers to saved or new recipients. Add `recipients:read`, `recipients:write`, `transfers:read`, and `transfers:write`.
Read price quotes and lock rates on the user's behalf. Add `quotes:read` and `quotes:write`. Note: locking a quote commits the partner to that rate — treat it as money movement.
## How the flow works
Authorization-code with PKCE is a four-leg exchange. The browser never sees a token — tokens are only exchanged server-to-server.
```
Browser Busha OAuth2 server Your backend
| | |
| GET /oauth2/auth | |
| (PKCE challenge, state) | |
|------------------------->| |
| Login + consent UI | |
|<------------------------>| |
| 302 → /callback?code=Z&state=... |
|---------------------------------------------------->|
| | POST /oauth2/token |
| | (code + verifier + secret)
| |<-------------------------|
| | access + refresh + id_token
| |------------------------->|
```
1. Your backend generates a PKCE verifier and CSRF state, then redirects the user's browser to `/oauth2/auth`.
2. The user logs in to Busha and consents on Busha's hosted screen.
3. Busha redirects the browser back to your callback URI with a one-time `code`.
4. Your backend exchanges the code (plus the PKCE verifier and your client secret) for tokens — server-to-server, never through the browser.
## Hosts and environments
| Environment | API host | OAuth2 issuer | Dashboard |
| ----------- | ---------------------- | ------------------------ | -------------- |
| Production | `api.busha.io` | `login.busha.io` | `app.busha.io` |
| Sandbox | `api.sandbox.busha.so` | `login.sandbox.busha.so` | `app.busha.io` |
The two environments are fully isolated — credentials, users, and tokens do not cross between them. Always read the canonical issuer string from `/.well-known/openid-configuration` at startup rather than hardcoding it.
## Next steps
Register your OAuth2 app and get your client credentials.
Make your first authorized API call end-to-end in minutes.
Browse all 12 scopes and pick only what you need.
Learn how access tokens, refresh tokens, and rotation work.
# Quick Start
Source: https://docs.busha.io/guides/oauth/quick-start
Go from zero to a working authorized API call in minutes. Steps 1–2 are dashboard setup; steps 3–6 are code.
This walkthrough assumes you have already [registered your OAuth2 app](./get-access) and have your `client_id` and `client_secret`. Pick one environment — sandbox or production — and use it throughout.
## Step 1 — Generate PKCE and CSRF values
Your backend generates a fresh PKCE verifier and CSRF state for every authorization request. Never reuse them.
```bash theme={null}
# Generate code_verifier
CODE_VERIFIER=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
# Derive code_challenge = base64url(sha256(code_verifier))
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
# Generate CSRF state (at least 16 random bytes)
STATE=$(openssl rand -hex 16)
```
Store `CODE_VERIFIER` and `STATE` in the user's server-side session — you'll need them in steps 3 and 4.
## Step 2 — Redirect the user to Busha
Build the authorization URL and redirect the user's browser to it. This is the only step that touches the browser.
```
https://login.busha.io/oauth2/auth
?response_type=code
&client_id=busha-oauth2-10d3cdb5-dda3-451a-87fc-9d6ccb0bb691-live
&redirect_uri=https%3A%2F%2Fyourapp.example.com%2Foauth2%2Fcallback
&scope=openid+offline_access+balances%3Aread+transactions%3Aread
&state=YOUR_STATE
&code_challenge=YOUR_CODE_CHALLENGE
&code_challenge_method=S256
```
| Parameter | Required | Value |
| ----------------------- | -------- | ------------------------------------------ |
| `response_type` | ✓ | `code` |
| `client_id` | ✓ | Your app's client ID |
| `redirect_uri` | ✓ | Byte-identical to a registered URI |
| `scope` | ✓ | Space-separated list of [scopes](./scopes) |
| `state` | ✓ | CSRF guard — bind to the user's session |
| `code_challenge` | ✓ | `base64url(sha256(code_verifier))` |
| `code_challenge_method` | ✓ | `S256` — `plain` is not accepted |
The user sees Busha's hosted login and consent screens. When they click **Authorize**, Busha redirects their browser back to your callback.
***
## Step 3 — Handle the callback
Busha redirects the user to:
```
https://yourapp.example.com/oauth2/callback?code=AbCdEf123XYZ&state=YOUR_STATE
```
Before doing anything with the `code`:
1. **Verify `state`** matches the value you stored in step 1. If it doesn't match, reject the request — this is a CSRF attack.
2. **Deduplicate** the `code` if your callback could fire twice (e.g. the user double-clicks). Codes are single-use; a second exchange attempt returns `invalid_grant`.
If the user clicks **Cancel** on the consent screen, Busha sends `?error=access_denied&state=...` instead. Render a "continue without connecting" path.
## Step 4 — Exchange the code for tokens
This call is server-to-server only. Never expose your `client_secret` or the token response to the browser.
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=$AUTH_CODE" \
--data-urlencode "redirect_uri=https://yourapp.example.com/oauth2/callback" \
--data-urlencode "code_verifier=$CODE_VERIFIER"
```
Successful response:
```json theme={null}
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "rt_5dG9HaP2mQ8kVnY4...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "openid offline_access balances:read transactions:read"
}
```
| Token | Returned when |
| --------------- | ---------------------------------- |
| `access_token` | Always |
| `refresh_token` | `offline_access` scope was granted |
| `id_token` | `openid` scope was granted |
Store `access_token` and `refresh_token` securely. See [Token handling](./tokens) for storage requirements and rotation.
## Step 5 — Call the Busha API
Attach the access token as a Bearer header:
```bash theme={null}
curl https://api.busha.io/v1/balances?currency=NGN \
-H "Authorization: Bearer $ACCESS_TOKEN"
```
```json theme={null}
{
"data": [
{ "currency": "NGN", "amount": "12345.67", "available": "12345.67" }
]
}
```
You are now calling Busha on the user's behalf.
## Step 6 — Keep the session alive with refresh
Access tokens expire in \~1 hour. Before `exp`, swap the refresh token for a new pair:
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "refresh_token=$REFRESH_TOKEN"
```
Refresh tokens rotate on every use. Persist the new `(access_token, refresh_token)` pair **before** discarding the old one. If persistence fails mid-call, you lose the session and must prompt the user to re-authorize. If you replay a previously-used refresh token, the entire token family is revoked immediately.
## What's next
Choose the right scopes for your integration and understand what each one does.
Validation, storage, rotation, and revocation in depth.
Full reference for all OAuth2 protocol endpoints.
Every error code, what causes it, and how to fix it.
# Scopes
Source: https://docs.busha.io/guides/oauth/scopes
All 12 OAuth2 scopes, what each one grants, and common combinations for different integration types.
Scopes define exactly what your app can do on a user's behalf. Busha has a flat allowlist of 12 scopes. Anything outside this list is rejected at registration with `invalid_scope`.
**Request only what your integration needs.** Users see your scope list on the consent screen — asking for more depresses conversion. Users can only Approve or Cancel the full bundle; they cannot cherry-pick individual scopes.
Admin approves your partner client overall (not per scope). After approval, `approved_scopes = requested_scopes`.
## Identity scopes
These are protocol-level scopes. Busha hides them from the consent screen, but they control whether you receive an `id_token` and a `refresh_token`. Request them if you want those tokens.
| Scope | What it grants |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `openid` | OIDC marker. Required for `id_token` issuance. |
| `offline_access` | Required for `refresh_token` issuance. Without it, the access token expires after one hour with no way to renew the session. |
## Wallets and balances
| Scope | What it grants |
| ------------------- | --------------------------------------------------- |
| `balances:read` | List the user's wallets and their current balances. |
| `transactions:read` | Read the user's transaction history. |
## Trading
| Scope | What it grants |
| -------------- | --------------------------------------------------------------------------------------- |
| `quotes:read` | Read price quotes. No rate commitment. |
| `quotes:write` | Lock a price quote. **This commits the partner to the rate — treat as money movement.** |
## Transfers
| Scope | What it grants |
| ----------------- | -------------------------------------------------------------------------- |
| `transfers:read` | Read the user's transfer history. |
| `transfers:write` | Initiate outgoing transfers on the user's behalf. **Real money movement.** |
## Wallet addresses
| Scope | What it grants |
| ----------------- | -------------------------------------------------- |
| `addresses:read` | Read the user's existing wallet deposit addresses. |
| `addresses:write` | Generate new deposit addresses for the user. |
## Recipients
| Scope | What it grants |
| ------------------ | ------------------------------------------------------------- |
| `recipients:read` | Read the user's saved transfer recipients. |
| `recipients:write` | Add, update, or delete saved recipients on the user's behalf. |
## Common combinations
| Integration type | Recommended scopes |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Read-only portfolio dashboard | `openid offline_access balances:read transactions:read` |
| Deposit flow | `openid offline_access balances:read addresses:read addresses:write` |
| Outbound transfers | `openid offline_access balances:read transactions:read recipients:read recipients:write transfers:read transfers:write` |
| FX / trading widget | `openid offline_access balances:read quotes:read quotes:write` |
Always include `openid` and `offline_access` in production integrations unless you deliberately want a single-session, one-hour token with no refresh capability.
# Security Best Practices
Source: https://docs.busha.io/guides/oauth/security
Customer funds are at stake. These requirements are not optional.
## PKCE is mandatory
Every authorization request must include `code_challenge` and `code_challenge_method=S256`. Generate a **fresh** `code_verifier` (43–128 URL-safe characters) per authorization request. `plain` challenges and missing challenges are rejected.
PKCE ensures that an attacker who intercepts the authorization code cannot redeem it without also possessing the verifier, which never leaves your backend.
## `state` is required for CSRF protection
Generate at least 16 bytes from a cryptographic RNG, bind the value to the user's session, and reject any callback where the returned `state` does not match. Without this guard, an attacker can plant a known authorization code on someone else's session.
## `nonce` for OIDC ID tokens
When you request `openid`, include a `nonce` parameter in the authorization request and validate it inside the `id_token`. This protects against ID-token replay attacks.
## `redirect_uri` must be exact
Register only redirect URIs your application controls. Production URIs must use HTTPS — HTTP is only allowed for `localhost`. Busha compares `redirect_uri` byte-for-byte:
* `https://app.example.com/cb` and `https://app.example.com/cb/` are **different URIs**.
* Port, scheme, path casing, and trailing slashes all matter.
* A mismatch is rejected immediately.
## `client_secret` belongs in your backend
Never place `client_secret` in:
* A mobile application
* A single-page application
* A browser extension
* Any code that ships to users
Store it in a secret manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager). If it is ever compromised, rotate it immediately using **Rotate Secret** on your app's dashboard page.
## Always verify access tokens before trusting them
Anyone can base64-decode a JWT and read its claims. None of those claims are trustworthy until you have verified the RS256 signature against the JWKS. See [Token handling → Validating access tokens](./tokens#validating-access-tokens) for the full validation checklist.
## Secure refresh token storage
Refresh tokens must be stored:
* **Encrypted at rest** with row-level encryption keyed per user.
* **Server-side only** — never in browser cookies or `localStorage`.
* Persisted **atomically** — write the new pair before discarding the old one.
## Revoke on disconnect
When a user disconnects your integration, call `POST /oauth2/revoke` with `token_type_hint=refresh_token`. This immediately prevents new tokens from being minted. The currently-issued access token continues to be valid until `exp`, but no new session can be started.
## Never log sensitive values
| Never log | Safe to log |
| -------------------- | ------------------- |
| `client_secret` | `client_id` |
| `access_token` | `jti` (JWT ID) |
| `refresh_token` | `sub` (user UUID) |
| `code_verifier` | Scope list |
| Authorization `code` | Request / trace IDs |
| `id_token` | |
# Token Handling
Source: https://docs.busha.io/guides/oauth/tokens
How to validate, store, rotate, and revoke Busha OAuth2 tokens.
## Token types at a glance
| Token | Format | Lifetime | Notes |
| --------------- | ------------- | ---------------- | --------------------------------------------------------------------------- |
| `access_token` | JWT (RS256) | \~1 hour | Validated locally. Cannot be revoked mid-flight — it self-expires at `exp`. |
| `refresh_token` | Opaque string | 30 days, sliding | Single-use. Rotates on every refresh. Replay revokes the entire family. |
| `id_token` | JWT (RS256) | \~1 hour | Identity proof only. Do not use as a bearer token on API calls. |
## Validating access tokens
Access tokens are JWTs signed with RS256. Validate them locally on every request — no per-request introspection round-trip to Busha.
Fetch public keys from `/.well-known/jwks.json`. Cache for \~5 minutes. Refetch when you encounter a `kid` (key ID) that is not in your cache.
```bash theme={null}
curl https://login.busha.io/.well-known/jwks.json
```
Read the canonical `issuer` string from `/.well-known/openid-configuration` at startup and pin against it — do not hardcode.
Match the JWT header's `kid` to a key in the JWKS. Verify the RS256 signature with that key.
Never decode an unverified JWT and trust its claims. A forged token looks identical until you check the cryptographic signature.
| Claim | Check |
| ----------- | ------------------------------------------------------------ |
| `iss` | Must match the canonical issuer from the discovery document. |
| `exp` | Must be in the future. Allow \~30 seconds of clock skew. |
| `aud` | Must include your `client_id` (if present). |
| `client_id` | Must match your registered `client_id`. |
Check the `scp` claim (a space-separated string or array depending on your library) against the scope required by the endpoint being called. A token with `scp="balances:read"` cannot call a transfers endpoint.
## Refreshing tokens
Every successful refresh issues a new `(access_token, refresh_token)` pair and immediately invalidates the old refresh token.
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "refresh_token=$REFRESH_TOKEN"
```
**Rotation rules:**
* Persist the new pair **atomically before** discarding the old one. If persistence fails, you lose the session.
* If a previously-rotated refresh token is replayed, Busha revokes the **entire token family** immediately.
* Any `invalid_grant` response on a refresh is a hard disconnect — prompt the user to re-authorize.
* The 30-day lifetime is **sliding**: each successful refresh resets the clock by another 30 days.
## Revoking tokens
When a user disconnects your integration, revoke the refresh token:
```bash theme={null}
curl -X POST https://login.busha.io/oauth2/revoke \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "token=$REFRESH_TOKEN" \
--data-urlencode "token_type_hint=refresh_token"
```
The endpoint returns `200` with an empty body whether or not the token was valid — this is intentional and prevents leaking token validity.
Revoking a refresh token prevents future refreshes immediately, but does not invalidate a currently-issued access token. The access token continues to validate until its `exp` (\~1 hour). For instant revocation on critical paths, consider maintaining a server-side allowlist that your backend checks.
## Storage requirements
| Token | Storage requirement |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `access_token` | In-memory or short-lived server-side cache. Never in browser localStorage or cookies. |
| `refresh_token` | Encrypted at rest, with row-level encryption keyed per user. Never in browser cookies or localStorage. |
| `client_secret` | Secret manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager). Never in source code or environment variables committed to version control. |
## What never to log
Never write these values to application logs, request logs, or error trackers:
* `client_secret`
* `access_token`
* `refresh_token`
* `code_verifier`
* Authorization `code`
* `id_token`
**Safe to log:** `client_id`, `jti`, `sub`, scope list, request IDs, trace IDs.
# Create Your First Payment Request
Source: https://docs.busha.io/guides/payment-requests/create-first-payment
Generate payment requests for customers. Accept crypto payments with fixed or variable amounts.
This guide will show you how to create a Payment Request on Busha. Use this feature to easily collect payments from your customers in both crypto and fiat, simplifying your payment process.
**What You'll Achieve:**
1. Create payment requests that generate crypto payment addresses
2. Handle common errors when creating requests
3. Learn the different essential parameters of a payment request
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Public API Key.
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
**Important Note:** Payment Requests use your Public API Key, not your Secret
API Key, as they're designed for customer-facing payment flows. Your Public
API Key is automatically generated for your account, you do not need to create
a new token to access it. You can find it in **Settings → Developer Tools →
API Tokens**.
## How to create your First Payment Request
Payment Requests are fundamentally different from Quotes because they're fiat-first: you specify the fiat amount you want to collect, and Busha calculates the equivalent crypto amount at current market rates.
**Essential Parameters**
Parameter
Data Type
Required/Optional
Description
quote\_currency
string
Required
The fiat currency for the payment amount
quote\_amount
string
Required
The fiat amount you're collecting from the customer
source\_currency
string
Required
The cryptocurrency the customer will pay with
target\_currency
string
Required
The cryptocurrency you'll receive
pay\_in
object
Required
Details about how the customer will pay
additional\_info
object
Required
Customer contact information
Let's create a payment request where a customer pays 50000 NGN worth of USDT.
To create a payment request:
1. Open your terminal or command prompt
2. Use the `POST` request below to the `/v1/payments/requests` endpoint
3. Replace `YOUR_BASE_URL` with your chosen environment's URL
4. Replace `{YOUR_PUBLIC_KEY}` with your actual Public API Key
```shell theme={null}
$ curl -X POST "YOUR_BASE_URL/v1/payments/requests" \
-H "X-BU-PUBLIC-KEY: {YOUR_PUBLIC_KEY}" \
-H "Content-Type: application/json" \
-d '{
"additional_info": {
"email": "john@busha.so",
"phone_number": "+234 8123456789"
},
"quote_amount": "50000",
"quote_currency": "NGN",
"source_currency": "USDT",
"target_currency": "USDT",
"pay_in": {
"type": "address",
"network": "TRX"
},
"reference": "order-2025-001"
}'
```
**Expected Response**
A successful response will return a Payment Request object with a unique crypto address for the customer to pay into:
```json theme={null}
{
"status": "success",
"message": "Payment request created sucessfully",
"data": {
"id": "PAYR_dGK3Xv7kCswk",
"additional_info": {
"email": "john@busha.so",
"phone_number": "+234 8123456789"
},
"created_at": "2025-09-01T14:53:25.902853715Z",
"expires_at": "2025-09-01T15:53:25.835834Z",
"fees": [],
"merchant_info": {
"email": "business@example.com",
"name": "Your Business Name"
},
"pay_in": {
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"expires_at": "2025-09-01T15:53:25.835834Z",
"network": "TRX",
"type": "address"
},
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USDT"
},
"reference": "order-2025-001",
"source_amount": "29.585432",
"status": "pending",
"target_amount": "29.585432",
"timeline": {
"total_steps": 2,
"current_step": 1,
"transfer_status": "pending",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your USDT payment",
"timestamp": "2025-09-01T14:53:25.747904Z"
},
{
"step": 2,
"done": false,
"status": "funds_received",
"title": "Payment Received",
"description": "We received your USDT Payment",
"timestamp": "2025-09-01T14:53:25.747904Z"
}
]
},
"updated_at": "2025-09-01T14:53:25.90285377Z",
"source_currency": "USDT",
"target_currency": "USDT"
}
}
```
**Key Response Fields:**
* **id:** The unique payment request ID
* **pay\_in.address:** The crypto address where customers send payment
* **source\_amount:** The calculated crypto amount customer must pay
* **expires\_at:** When the payment request expires
## Understanding the Payment Timeline
Payment Requests include a timeline object showing the payment progress:
* **Step 1: "Transfer Started"** - Payment request created, waiting for customer payment
* **Step 2: "Payment Received"** - Customer has sent the cryptocurrency to the provided address
Monitor the `timeline.current_step` to track payment progress using a Webhook.
## Troubleshooting
* **Offline Product:** "This pair is currently unavailable to trade." Try a different `source_currency` or check the Pairs API for currently available pairs.
* **`401 Unauthorized`:** Double-check that your public API key is correct.
## What's Next?
Now that you have successfully created a payment request, check out the following guides:
* [How to Retrieve Payment Requests](/guides/payment-requests/retrieve-payment)
* [How to Set Up Webhooks](/guides/webhooks/setup)
* [How to Create A Quote](/guides/quotes/create-first-quote)
* [Supported Currencies Reference](/guides/reference/supported-currencies): See available cryptocurrency and fiat pairs
* [API Reference: Payment Request Object](/api-reference/paymentrequests/create-a-payment-request): For a complete list of all parameters, sub-fields for a payment request
# Retrieve Payment Request
Source: https://docs.busha.io/guides/payment-requests/retrieve-payment
Fetch payment request details and status. Monitor payment completion and customer information.
After successfully creating a Payment Request, a unique `id` is returned in the API response. This Payment Request ID is essential for monitoring payment status and retrieving customer payment details. This guide will show you how to use this ID to retrieve the full details and current status of any existing payment request.
**What You'll Achieve:**
1. Understand why and when to retrieve payment request information
2. Successfully make an API request to fetch a specific payment request
3. Interpret the comprehensive Payment Request response, including payment timeline
4. Monitor customer payment progress and status changes
## Prerequisites
Before you begin, ensure that you have:
* A Busha Business Account and Public API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
**Important Note:** Payment Requests use your Public API Key, not your Secret
API Key, as they're designed for customer-facing payment flows. Your Public
API Key is automatically generated for your account you do not need to create
a new token to access it. You can find it in **Settings → Developer Tools →
API Tokens**.
## How to Retrieve Payment Requests
To retrieve payment request information, you'll use the `GET` method on the `/v1/payments/requests/{id}` endpoint. This endpoint allows you to query the current state and details of a specific payment request by providing its unique ID.
**Why Retrieve a Payment Request?**
* **Monitor Payment Status:** Check if the customer has completed their cryptocurrency payment
* **Get Payment Details:** Retrieve the crypto address and amount for customer instructions
* **Track Payment Timeline:** Monitor progress through the payment flow steps
* **Confirm Payment Completion:** Verify when funds have been received
Use the `GET` request below, replacing the placeholders with your actual values.
To retrieve payment request information:
1. Open your terminal or command prompt
2. Construct a `GET` request to the `/v1/payments/requests/{id}` endpoint
3. Replace `YOUR_BASE_URL` with your chosen environment's URL (e.g., `https://api.sandbox.busha.so`)
4. Replace `{id}` with the actual ID of the payment request you wish to retrieve (e.g., `PAYR_dGK3Xv7kCswk`)
5. Replace `{YOUR_PUBLIC_KEY}` with your actual Public API Key
```shell theme={null}
$ curl --request GET \
--url YOUR_BASE_URL/v1/payments/requests/{id} \
--header 'X-BU-PUBLIC-KEY: {YOUR_PUBLIC_KEY}'
```
**Example:**
```shell theme={null}
$ curl "https://api.sandbox.busha.so/v1/payments/requests/PAYR_dGK3Xv7kCswk" \
-H "X-BU-PUBLIC-KEY: pub_iSQAgqGFoVZOaVjYM1UeW"
```
Upon a successful request, the API will return the complete Payment Request object, including any status updates since creation.
**Expected Response:**
```json theme={null}
{
"status": "success",
"message": "Payment request retrieved successfully",
"data": {
"id": "PAYR_dGK3Xv7kCswk",
"additional_info": {
"email": "john@busha.so",
"phone_number": "+254 701234567"
},
"created_at": "2025-09-01T14:53:25.902853Z",
"expires_at": "2025-09-01T15:53:25.835834Z",
"fees": [],
"merchant_info": {
"email": "business@example.com",
"name": "Your Business Name"
},
"pay_in": {
"address": "TTc5HBAEETmqPTarVUU3xLB3fY7b1YxNzm",
"expires_at": "2025-09-01T15:53:25.835834Z",
"network": "TRX",
"type": "address"
},
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "USDT"
},
"reference": "test-payment-real-001",
"source_amount": "19.423511",
"status": "pending",
"target_amount": "19.423511",
"timeline": {
"total_steps": 2,
"current_step": 1,
"transfer_status": "pending",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your USDT payment",
"timestamp": "2025-09-01T14:53:25.747904Z"
},
{
"step": 2,
"done": false,
"status": "funds_received",
"title": "Payment Received",
"description": "We received your USDT Payment",
"timestamp": "2025-09-01T14:53:25.747904Z"
}
]
},
"updated_at": "2025-09-01T14:53:25.981519Z",
"source_currency": "USDT",
"target_currency": "USDT"
}
}
```
**Key Response Fields Explained:**
**Payment Status:**
* **status:** Current payment status
* **expires\_at:** When the payment request expires
* **updated\_at:** Last time the payment request was modified
## Troubleshooting
* **Expired Quote:** If `expires_at` is in the past it cannot be used. You will need to create a new payment request.
* **401 Unauthorized:** Double-check that your public API key is correct.
## What's Next?
Now that you can retrieve payment request information, you can use this ID:
* [How to Create Payment Requests](/guides/payment-requests/create-first-payment)
* [How to Set Up Webhooks](/guides/webhooks/setup)
* [How to Create A Quote](/guides/quotes/create-first-quote)
* [Supported Currencies Reference](/guides/reference/supported-currencies): See available cryptocurrency and fiat pairs
* [API Reference: Payment Request Object](/api-reference/paymentrequests/create-a-payment-request): For a complete list of all parameters, sub-fields for a payment request
# Process Crypto Payouts
Source: https://docs.busha.io/guides/payouts/process-crypto-payouts
Send cryptocurrency payouts to blockchain addresses.
This guide will walk you through the process of programmatically making crypto withdrawals (Off-Ramp) from your Busha Business crypto balances. Payouts, like all transfers, require a Quote to define the transaction terms and a pre-configured Recipient to specify the destination.
**What You'll Achieve:**
1. Understand the prerequisites of creating a recipient for payouts.
2. Generate a specific Quote for a crypto-to-crypto payout.
3. Execute the payout transfer from your Busha crypto balance to your crypto wallet.
4. Monitor the status of your payout.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of **API Environments** (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
* A conceptual understanding of **Quotes** (from the [Understanding Quotes](/overview/quotes) Overview).
* Familiarity with creating basic quotes (from the [How to Create Your First Quote Guide](/guides/quotes/create-first-quote)).
For payout requests involving a customer, the `X-BU-PROFILE-ID` field should
be included in the request header, and its value should be set to the customer
ID for whom the request is performed on their behalf.
## How to Process Crypto to Crypto Payouts
For crypto payouts, Busha requires a valid address, network and memo (for networks that mandate a memo for cryptocurrency transactions) in the `pay_out` object of your quote.
Your `pay_out` object should look like this:
```json theme={null}
"pay_out": {
"type": "address",
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"network": "BTC"
}
```
The network type must be in uppercase, e.g., BTC, USDT, TRX.
The next step is to create a Quote for your payout. This quote will specify the cryptocurrency you're withdrawing from (`source_currency`), the cryptocurrency the recipient will receive (`target_currency`), the amount, and importantly, the `pay_out` object with the recipient details.
To create a payout quote:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/quotes` endpoint.
3. Set the type to "withdrawal".
4. Specify `source_currency` (e.g., BTC), `target_currency` (e.g., BTC), and either `source_amount` or `target_amount` (e.g., `target_amount: "100"` the recipient should receive).
5. Include the `pay_out` object you prepared in Step 1.
6. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_KEY`.
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "BTC",
"target_currency": "btc",
"target_amount": "0.0001",
"pay_out": {
"type": "address",
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"network": "BTC"
}
}'
```
For sandbox requests, you can obtain test addresses from any of the providers
listed in the Test Addresses reference.
**Expected Quote Response**
A successful response will return a Quote object, detailing the `id` of the quote, the calculated `source_amount` (how much crypto you'll need to send if you provided `target_amount`), the rate, associated fees, and the `expires_at` timestamp. Importantly, the `pay_out` object will include recipient\_details confirming the destination account information.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_mZrlSnIFzGkA",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"target_amount": "0.0001",
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [],
"pay_out": {
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"network": "BTC",
"type": "address"
},
"reference": "QUO_mZrlSnIFzGkA",
"status": "pending",
"created_at": "2025-06-18T16:58:12.762193733Z",
"updated_at": "2025-06-18T16:58:12.762193733Z"
}
}
```
This is the final step where you initiate the actual withdrawal from your Busha crypto balance to the specified crypto wallet. You do this by creating a Transfer using the `quote_id` obtained in Step 2.
To create the payout transfer:
1. Use the `POST` request below to the `/v1/transfers` endpoint.
2. Include the `quote_id` obtained from Step 2 in the request body.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_KEY` with your actual details.
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_mZrlSnIFzGkA"
}'
```
**Expected Transfer Response**
A successful response will return a Transfer object, containing the same information as the quote, plus the `id` of the transfer (e.g., `TRF_tYZ1y5bmXv4N5IhXSMbWJ`) and its current status. For payouts, the status will typically start as `pending` and change as the payout is processed.
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_4VJeKDm6Ow2V",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"quote_id": "QUO_mZrlSnIFzGkA",
"description": "Sold BTC",
"sub_description": "For BTC",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"target_amount": "0.0001",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [],
"pay_out": {
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"network": "BTC",
"type": "address"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-06-18T17:00:37.695327321Z",
"updated_at": "2025-06-18T17:00:37.695327373Z"
}
}
```
For payouts, it's crucial to monitor the transfer's status to confirm successful delivery of funds to the recipient.
To monitor payout status:
* **Webhooks (Recommended):** Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes (e.g., from `pending` to `completed` or `failed`). This is the most efficient method for real-time updates. Refer to the [How to Set Up Webhooks Guide](/guides/webhooks/setup) for detailed instructions.
* **Polling (Less Recommended):** Periodically GET the transfer status using the transfer `id` (`TRF_tYZ1y5bmXv4N5IhXSMbWJ` in the example). While possible, this is less efficient and can lead to rate limiting if done too frequently.
```bash theme={null}
curl -X GET "YOUR_BASE_URL/v1/transfers/TRF_4VJeKDm60w2V" -H "Authorization: Bearer {YOUR_SECRET_API_KEY}"
```
**Expected Transfer Statuses**
* **pending:** Transfer initiated, awaiting user bank transfer.
* **processing:** This means the funds has been received, and is being handled.
* **funds\_delivered:** Funds have been successfully received and credited to your Busha balance.
* **cancelled:** The transfer has been cancelled, and will not continue.
## Troubleshooting
**Common Payout Issues:**
* **"Quote expired" during transfer creation:** Always generate a fresh quote immediately before attempting to create the transfer.
* **"Insufficient balance":** Ensure your Busha account has enough `source_currency` to cover the `source_amount` in the quote.
* **`401 Unauthorized`:** Verify your Authorization header and API key.
## What's Next?
Now that you know how to make payouts, you can explore other transaction types or manage recipients:
* [How to Process Fiat Payouts](/guides/payouts/process-payouts)
* [How to Perform Balance-to-Balance Conversions Guide](/guides/balance/convert-balance-to-balance)
* [Quotes API Reference](/api-reference/quotes/list-quotes)
* [Transfers API Reference](/api-reference/transfers/list-transfers)
# Process Payouts
Source: https://docs.busha.io/guides/payouts/process-payouts
Send payouts to bank accounts and mobile money.
This guide will walk you through the process of programmatically making withdrawals (Off-Ramp) from your Busha Business crypto balances to fiat destinations like bank accounts or mobile money wallets. Payouts, like all transfers, require a Quote to define the transaction terms and a pre-configured Recipient to specify the destination.
**What You'll Achieve:**
1. Understand the prerequisites of creating a recipient for payouts.
2. Generate a specific Quote for a crypto-to-fiat payout.
3. Execute the payout transfer from your Busha crypto balance to fiat account.
4. Monitor the status of your payout.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start)).
* An understanding of **API Environments** (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
* A conceptual understanding of **Quotes** (from the [Understanding Quotes](/overview/quotes) Overview).
* Familiarity with creating basic quotes (from the [How to Create Your First Quote Guide](/guides/quotes/create-first-quote)).
* An existing **recipient ID** for the bank account or mobile money wallet you wish to send funds to. If you don't have one, please refer to the [How to Create Recipients Guide](/guides/recipients/create-and-manage).
For payout requests involving a customer, the `X-BU-PROFILE-ID` field should
be included in the request header, and its value should be set to the customer
ID for whom the request is performed on their behalf.
## How to Process Crypto to Fiat Payouts
For `bank_transfer` or `mobile_money` payouts, Busha requires an existing `recipient_id` within the `pay_out` object of your quote. This ensures that the destination account has been previously verified and is associated with your profile, streamlining the payout process.
If you haven't already, you must create a recipient for the specific bank account or mobile money wallet you intend to send funds to.
For detailed instructions on creating and managing recipients, please refer to the [How to Create and Manage Recipients Guide](/guides/recipients/create-and-manage).
Once you have a `recipient_id`, your `pay_out` object will look similar to this example:
```json theme={null}
"pay_out": {
"type": "bank_transfer", // or "mobile_money"
"recipient_id": "677bbf9c7cf061f23784555a" // Replace your actual recipient ID
}
```
With your `recipient_id` in hand, the next step is to create a Quote for your payout. This quote will specify the cryptocurrency you're withdrawing from (`source_currency`), the fiat currency the recipient will receive (`target_currency`), the amount, and importantly, the `pay_out` object with the recipient details.
To create a payout quote:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/quotes` endpoint.
3. Set the type to "withdrawal".
4. Specify `source_currency` (e.g., USDT), `target_currency` (e.g., NGN), and either `source_amount` or `target_amount` (e.g., `target_amount: "100"` NGN the recipient should receive).
5. Include the `pay_out` object with the type and `recipient_id` you prepared in Step 1.
6. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_KEY`.
```bash theme={null}
curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "USDT",
"target_currency": "NGN",
"target_amount": "100",
"pay_out": {
"type": "bank_transfer",
"recipient_id": "677bbf9c7cf061f23784555a"
}
}'
```
**Expected Quote Response**
A successful response will return a Quote object, detailing the `id` of the quote, the calculated `source_amount` (how much crypto you'll need to send if you provided `target_amount`), the rate, associated fees, and the `expires_at` timestamp. Importantly, the `pay_out` object will include `recipient_details` confirming the destination account information.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_mprvCPMCfm3K2qSnzbWj7",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "168876",
"rate": {
"product": "USDTNGN",
"rate": "1690.76",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "200",
"currency": "NGN"
},
"name": "Fees",
"type": "FIXED"
}
],
"pay_out": {
"recipient_details": {
"account_name": "SOSANYA DICKSON OLUMIDE",
"account_number": "2109328188",
"bank_name": "UNITED BANK FOR AFRICA",
"country": "NG"
},
"recipient_id": "677bbf9c7cf061f2b784555a",
"type": "bank_transfer"
},
"reference": "QUO_mprvCPMCfm3K2qSnzbWj7",
"status": "pending",
"expires_at": "2025-02-20T10:58:19.540052923Z",
"created_at": "2025-02-20T10:28:19.540025003Z",
"updated_at": "2025-02-20T10:28:19.540025003Z"
}
}
```
This is the final step where you initiate the actual withdrawal from your Busha crypto balance to the specified fiat recipient. You do this by creating a Transfer using the `quote_id` obtained in Step 2.
To create the payout transfer:
1. Use the `POST` request below to the `/v1/transfers` endpoint.
2. Include the `quote_id` obtained from Step 2 in the request body.
3. Replace `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/transfers \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"quote_id": "QUO_Nm2EBRxmuHGdTyGnVNDUt"
}'
```
**Expected Transfer Response**
A successful response will return a Transfer object, containing the same information as the quote, plus the `id` of the transfer (e.g., `TRF_tYZ1y5bmXv4N5IhXSMbWJ`) and its current status. For payouts, the status will typically start as `pending` and change as the payout is processed.
```json theme={null}
{
"status": "success",
"message": "Created transfer successfully",
"data": {
"id": "TRF_tYZ1y5bmXv4N5IhXSMbWJ",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"quote_id": "QUO_mprvCPMCfm3K2qSnzbWj7",
"source_currency": "USDT",
"target_currency": "NGN",
"source_amount": "100",
"target_amount": "168876",
"rate": {
"product": "USDTNGN",
"rate": "1690.76",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "200",
"currency": "NGN"
},
"name": "Fees",
"type": "FIXED"
}
],
"pay_out": {
"recipient_details": {
"account_name": "SOSANYA DICKSON OLUMIDE",
"account_number": "2109328188",
"bank_name": "UNITED BANK FOR AFRICA",
"country": "NG"
},
"recipient_id": "677bbf9c7cf061f2b784555a",
"type": "bank_transfer"
},
"status": "pending",
"created_at": "2025-02-20T10:28:42.376910852Z",
"updated_at": "2025-02-20T10:28:42.376910905Z"
}
}
```
For payouts, it's crucial to monitor the transfer's status to confirm successful delivery of funds to the recipient.
To monitor payout status:
* **Webhooks (Recommended):** Set up a webhook endpoint to receive real-time notifications from Busha when the transfer status changes (e.g., from `pending` to `completed` or `failed`). This is the most efficient method for real-time updates. Refer to the [How to Set Up Webhooks Guide](/guides/webhooks/setup) for detailed instructions.
* **Polling (Less Recommended):** Periodically GET the transfer status using the transfer `id` (`TRF_tYZ1y5bmXv4N5IhXSMbWJ` in the example). While possible, this is less efficient and can lead to rate limiting if done too frequently.
```bash theme={null}
curl -X GET "YOUR_BASE_URL/v1/transfers/TRF_tYZ1y5bmXv4N5IhXSMbWJ" -H "Authorization: Bearer {YOUR_SECRET_API_KEY}"
```
**Expected Transfer Statuses**
* **pending:** Transfer initiated, awaiting user bank transfer.
* **processing:** This means the funds has been received, and is being handled.
* **funds\_delivered:** Funds have been successfully received and credited to your Busha balance.
* **cancelled:** The transfer has been cancelled, and will not continue.
## Troubleshooting
**Common Payout Issues:**
* **"Quote expired" during transfer creation:** Always generate a fresh quote immediately before attempting to create the transfer.
* **"Insufficient balance":** Ensure your Busha account has enough `source_currency` to cover the `source_amount` in the quote.
* **Invalid Recipient ID:** Double-check that the `recipient_id` in your `pay_out` object is correct and active. An invalid ID will cause the transfer to fail.
* **Payout delayed:** Bank transfers can sometimes take longer than crypto transfers due to banking hours or processing times. Monitor status via webhooks. If prolonged, contact Busha support.
* **`401 Unauthorized`:** Verify your Authorization header and API key.
## What's Next?
Now that you know how to make payouts, you can explore other transaction types or manage recipients:
* [How to Create and Manage Recipient Guide](/guides/recipients/create-and-manage): Essential for managing your payout destinations.
* [How to Process Fiat Deposits Guide](/guides/deposits/process-fiat-deposits)
* [How to Process Crypto Deposits Guide](/guides/deposits/process-crypto-deposits)
* [How to Perform Balance-to-Balance Conversions Guide](/guides/balance/convert-balance-to-balance)
* [Quotes API Reference](/api-reference/quotes/list-quotes)
* [Transfers API Reference](/api-reference/transfers/list-transfers)
# Busha Pledges
Source: https://docs.busha.io/guides/pledges/introduction
Let a customer lock their own Busha assets as collateral for a credit agreement with your business, without ever taking custody of those assets yourself.
## What are Pledges?
Pledges let a Busha customer lock a portion of their own crypto balance as collateral for a credit agreement with your business: a loan, a line of credit, or any arrangement where you need security against funds you don't hold.
The customer's assets stay in their own Busha account. They're never transferred to you. Busha locks them in place for the duration of the agreement, releases them as the customer repays, and if the customer defaults, lets you request liquidation under a notice period defined by the pledge mandate.
Three parties are involved in every pledge:
* **The customer** owns the assets and must authorize the pledge themselves via OAuth2
* **The beneficiary** is your business, the counterparty benefiting from the collateral
* **Busha** is the custodian enforcing the lock and mediating the lifecycle
Pledges require [Busha OAuth2](/guides/oauth/introduction). Unlike most
Business API resources, a pledge cannot be created with a business Secret Key
alone. Busha needs cryptographic proof that the customer consented to the
specific assets being locked.
## Why OAuth2, not a Secret Key
Every other resource in the Business API, quotes, transfers, customer management, either belongs to your business directly, or to a customer you created and administer via `X-BU-PROFILE-ID`. Pledges are different: the assets belong to an independent Busha user with their own login, outside your administration.
To lock those assets, your app must obtain an access token through the OAuth2 authorization code flow, with the customer completing login and consent on Busha's own hosted screen. Calling a pledge endpoint with a business Secret Key instead of a customer scoped OAuth2 token returns a `request_validation` error.
## Before you begin
Pledges sit on top of OAuth2, so make sure you have:
* A **Busha business account** with completed KYB (Know Your Business) verification.
* An **OAuth2 app** registered under your business account. See [Get access](/guides/oauth/get-access).
* The **pledge scopes** your integration needs, requested at OAuth2 app registration. See [Scopes](/guides/oauth/scopes#pledges).
* A **pledge configuration** enabled for your business account. This is set up on Busha's side, contact your integration manager if `pledges/quotes` returns `Pledge config not found`.
## The pledge scopes
| Scope | What it grants |
| ------------------- | ----------------------------------------------------------------------------------- |
| `pledges:read` | View pledge records, item status, and lifecycle events. |
| `pledges:write` | Create pledge quotes, lock approved assets, activate pledges, add or release items. |
| `pledges:liquidate` | Request or cancel liquidation of pledged assets. |
## The pledge lifecycle
A pledge moves through the following states over its lifetime:
| Status | Meaning |
| --------------------- | -------------------------------------------------------------------------- |
| `authorized` | Collateral locked. The credit agreement has not yet been confirmed active. |
| `active` | Beneficiary confirmed disbursement, the agreement is live. |
| `liquidation_pending` | A liquidation has been requested and is inside its notice period. |
| `released` | All pledged assets have been returned to the customer. |
| `liquidated` | Pledged assets were seized following a completed liquidation. |
| `expired` | The pledge lapsed before being activated. |
| `cancelled` | The pledge was called off before going active. |
A pledge quote and the pledge it creates both carry a short `expires_at`
window. If you don't call [Activate
pledge](/api-reference/pledges/create-pledge-quote#activate-pledge) before that window closes,
the pledge becomes unusable. Build your disbursement flow to activate
immediately after creating the pledge, not after external processing.
Each individual pledged item (one per asset in a multi asset pledge) tracks its own finer grained status as it's released or liquidated:
| Item status | Meaning |
| ---------------------- | --------------------------------------- |
| `locked` | Fully locked, untouched. |
| `partially_released` | Some has been returned to the customer. |
| `released` | Fully returned. |
| `partially_liquidated` | Some has been seized. |
| `liquidated` | Fully seized. |
## A typical integration
A lending product built on Pledges follows roughly this shape:
1. Your customer requests credit, offering their Busha crypto as collateral.
2. They authorize your app via OAuth2, consenting to the pledge scopes you requested.
3. You create a [pledge quote](/guides/pledges/quick-start#1-create-a-pledge-quote) to confirm the assets can be locked.
4. You [create the pledge](/guides/pledges/quick-start#2-create-the-pledge) from that quote and immediately [activate it](/guides/pledges/quick-start#3-activate-the-pledge) once you've disbursed funds.
5. As the customer repays, you [release](/api-reference/pledges/create-pledge-quote#release-pledge-items) collateral back to them, partially or in full.
6. If the customer defaults, you [request liquidation](/api-reference/pledges/create-pledge-quote#request-pledge-liquidation), which executes automatically after a notice period unless you [cancel it](/api-reference/pledges/create-pledge-quote#cancel-pledge-liquidation).
## Next steps
Walk through a full pledge lifecycle end to end, from quote to liquidation.
Full reference for every pledge endpoint, parameters, responses, and
required scopes.
Review the pledge scopes alongside the rest of the OAuth2 scope catalog.
# Quick Start
Source: https://docs.busha.io/guides/pledges/quick-start
Walk through a full pledge lifecycle end to end, and every error you might hit along the way.
## Before you start
A pledge is created on the customer's behalf, so you need a customer scoped OAuth2 access token before you touch any pledge endpoint. If you already have one and it still carries the pledge scopes you need, skip to [step 1](#1-create-a-pledge-quote).
Getting that token means walking through the OAuth2 authorization code flow once. Here's the brief version of what you're doing and where to go for each part:
**1. Generate PKCE values.** Your backend creates a fresh `code_verifier`, its derived `code_challenge`, and a CSRF `state` value for this specific authorization attempt. Never reuse these across attempts.
```bash theme={null}
CODE_VERIFIER=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
STATE=$(openssl rand -hex 16)
```
Full detail on why PKCE matters is in [Security best practices](/guides/oauth/security#pkce-is-mandatory).
**2. Send the customer to authorize your app.** Build the authorization URL with your `client_id`, `redirect_uri`, the pledge scopes you need, and the `code_challenge` and `state` from step 1. The customer logs in and consents on Busha's own screen, then gets redirected back to you with a `code`. See [Quick start: Step 2](/guides/oauth/quick-start#step-2-redirect-the-user-to-busha) for the exact URL shape.
**3. Exchange the code for tokens.** Your backend swaps the `code` for an `access_token` and `refresh_token`, using the `code_verifier` from step 1. See [Quick start: Step 4](/guides/oauth/quick-start#step-4-exchange-the-code-for-tokens).
**4. Check the token has the pledge scopes you need.** The response's `scope` field lists what was actually granted. If `pledges:liquidate` isn't there and you'll need it later, request it now rather than re running this whole flow later, see [Scopes](/guides/oauth/scopes#pledges).
Don't have an OAuth2 app yet, or need your `client_id`/`client_secret`? Start at [Get access](/guides/oauth/get-access).
Codes are single use and expire in 10 minutes. Access tokens expire in about
an hour, refresh tokens rotate on every use. If a pledge request suddenly
returns `401`, refresh rather than restarting the whole flow, see [Token
handling](/guides/oauth/tokens).
## 1. Create a pledge quote
Before locking anything, preflight the request. This confirms the customer's assets are available to lock without moving funds.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/quotes \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "credit_agreement_93b7",
"items": [
{ "asset": "USDT", "amount": "100" }
]
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge quote created successfully",
"data": {
"id": "PLQ_iF6AVNpqi71h",
"status": "quoted",
"expires_at": "2026-07-16T15:34:03.681633Z",
"reference": "credit_agreement_93b7",
"can_create": true,
"items": [{ "asset": "USDT", "amount": "100", "can_lock": true }]
}
}
```
Check `can_create` and each item's `can_lock` before proceeding. A `false` value means that asset can't currently be locked for this customer.
## 2. Create the pledge
Using the quote's `id`, lock the assets.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "PLQ_iF6AVNpqi71h"
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge created successfully",
"data": {
"id": "PLG_zyGKA90DLjiA",
"status": "authorized",
"reference": "credit_agreement_93b7",
"customer_profile_id": "a8002eb5-e170-4a33-9ab1-43f53532676e",
"beneficiary_profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"mandate_hash": "sha256:9969916fb37d5cb275fea31b2bae3982781cc7c59ce0ac89456dd14c8ca840ed",
"expires_at": "2026-07-16T15:34:03.681633Z",
"items": [
{
"id": "PLI_OdfLCpvbqTU3",
"asset": "USDT",
"locked_amount": "100",
"released_amount": "0",
"liquidated_amount": "0",
"available_to_release": "100",
"status": "locked"
}
],
"events": [
{
"id": "PLE_jssHLw5HgjdC",
"type": "pledge.created",
"actor_type": "customer",
"reference": "credit_agreement_93b7",
"created_at": "2026-07-16T15:33:06.419377Z"
}
]
}
}
```
The customer's USDT is now locked. Save the pledge `id`, you'll need it for every subsequent call.
Activate the pledge immediately after creating it. The pledge inherits its
quote's `expires_at`, and `activate` will reject once that window closes.
## 3. Activate the pledge
Once you've disbursed the credit to the customer, confirm the agreement is live.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/PLG_zyGKA90DLjiA/activate \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "activation_disb_9f1"
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge activated successfully",
"data": {
"id": "PLG_zyGKA90DLjiA",
"status": "active",
"activated_at": "2026-07-16T16:26:31.273764Z",
"event_id": "PLE_v1zivzYjJQZW"
}
}
```
## 4. Add pledge items
Grow a pledge into a multi asset pledge, or add more of an asset already on the pledge.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/PLG_zyGKA90DLjiA/items \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "topup_7af2",
"items": [
{ "asset": "NGN", "amount": "25000" }
],
"reason": "beneficiary_requested_top_up"
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge items added successfully",
"data": {
"id": "PLG_zyGKA90DLjiA",
"status": "active",
"items": [
{
"id": "PLI_OdfLCpvbqTU3",
"asset": "USDT",
"locked_amount": "100",
"released_amount": "0",
"liquidated_amount": "0",
"available_to_release": "100",
"status": "locked"
},
{
"id": "PLI_pu1OE5fOsvCz",
"asset": "NGN",
"locked_amount": "25000",
"released_amount": "0",
"liquidated_amount": "0",
"available_to_release": "25000",
"status": "locked"
}
],
"event_id": "PLE_fotEJyQDJnRi"
}
}
```
## 5. Release collateral as the customer repays
Each time the customer makes a repayment, release the corresponding share of collateral. Set `full_release: true` once the agreement is fully repaid.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/PLG_zyGKA90DLjiA/release \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "release_rel_901",
"full_release": false,
"reason": "partial_repayment",
"items": [
{ "pledge_item_id": "PLI_OdfLCpvbqTU3", "amount": "20" }
]
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge released successfully",
"data": {
"id": "PLG_zyGKA90DLjiA",
"status": "active",
"released_items": [
{
"pledge_item_id": "PLI_OdfLCpvbqTU3",
"asset": "USDT",
"released_amount": "20",
"remaining_locked_amount": "80"
}
],
"event_id": "PLE_ei7aPWLHp0zi"
}
}
```
## 6. List and get pledges
```bash theme={null}
curl -X GET https://api.busha.io/v1/pledges \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN"
```
```json theme={null}
{
"status": "success",
"message": "Pledges retrieved successfully",
"data": [
{
"id": "PLG_zyGKA90DLjiA",
"status": "active",
"reference": "credit_agreement_93b7",
"customer_profile_id": "a8002eb5-e170-4a33-9ab1-43f53532676e",
"beneficiary_profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"activated_at": "2026-07-16T16:26:31.273764Z",
"expires_at": "2026-07-16T15:34:03.681633Z"
}
],
"pagination": { "current_entries_size": 1 }
}
```
```bash theme={null}
curl -X GET https://api.busha.io/v1/pledges/PLG_zyGKA90DLjiA \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN"
```
```json theme={null}
{
"status": "success",
"message": "Pledge retrieved successfully",
"data": {
"id": "PLG_zyGKA90DLjiA",
"status": "active",
"reference": "credit_agreement_93b7",
"customer_profile_id": "a8002eb5-e170-4a33-9ab1-43f53532676e",
"beneficiary_profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"mandate_hash": "sha256:e86ce63cf627eb1f7759cbd7474a24066697261027e3b41d1e89c9ec9f52d7a3",
"items": [
{
"id": "PLI_5VXlrc4dT34U",
"asset": "USDT",
"locked_amount": "80",
"released_amount": "20",
"liquidated_amount": "0",
"available_to_release": "80",
"status": "locked"
}
],
"events": []
}
}
```
Use `GET /v1/pledges/{id}` when you need the full items array. `GET /v1/pledges` (list) is best for browsing and filtering across many pledges.
## 7. Request and cancel liquidation
If the customer defaults, request liquidation. This requires the `pledges:liquidate` scope, requested separately from `pledges:write` and `pledges:read` at authorization time.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/PLG_zyGKA90DLjiA/liquidations \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "default_case_348",
"reason": "default_under_beneficiary_terms",
"beneficiary_due": { "amount": "30", "currency": "USDT" },
"items": [
{ "pledge_item_id": "PLI_5VXlrc4dT34U", "amount": "30" }
],
"evidence": {
"missed_payments": 2,
"notes": "customer missed two consecutive repayments"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge liquidation requested successfully",
"data": {
"id": "PLR_kO8ErlYYALPO",
"pledge_id": "PLG_btRodtIrderK",
"status": "pending_execution",
"notice_period_seconds": 86400,
"execute_after": "2026-07-18T09:53:23.943401Z",
"beneficiary_due": { "amount": "30", "currency": "USDT" },
"created_at": "2026-07-17T09:53:23.947377Z"
}
}
```
The liquidation does not execute immediately. It sits in `pending_execution` until `execute_after`, giving the customer time to resolve the default.
```bash theme={null}
curl -X POST https://api.busha.io/v1/pledges/PLG_btRodtIrderK/liquidations/PLR_kO8ErlYYALPO/cancel \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reference": "cancel_default_case_348",
"reason": "customer_repaid"
}'
```
```json theme={null}
{
"status": "success",
"message": "Pledge liquidation cancelled successfully",
"data": {
"id": "PLR_kO8ErlYYALPO",
"pledge_id": "PLG_btRodtIrderK",
"status": "cancelled",
"cancelled_at": "2026-07-17T09:54:17.108889Z",
"event_id": "PLE_9MnJOklrhaF5"
}
}
```
## Errors
Pledge endpoints return the standard Busha error envelope. See [OAuth2 Errors](/guides/oauth/errors) for authorization layer failures like `invalid_grant` or `insufficient_scope`.
| Error | Cause | Fix |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `request_validation`, "Invalid pledge identity" | The request used a business Secret Key, or an OAuth2 token without a valid customer identity attached. | Authenticate with a customer scoped OAuth2 access token. See [Before you begin](/guides/pledges/introduction#before-you-begin). |
| `resource_state_conflict`, "Pledge is not in the required state" | Most commonly, the pledge's `expires_at` window closed before you called activate. Can also occur when an action is attempted against a pledge in an incompatible status. | Activate the pledge immediately after creating it. Check the pledge's current `status` via Get pledge before retrying. |
| `Forbidden`, "oauth2: missing required scope" | The access token doesn't carry the scope the endpoint requires, most often `pledges:liquidate` on the liquidation endpoints. | Re-run the OAuth2 authorization flow requesting the missing scope. See [Scopes](/guides/oauth/scopes#pledges). |
| `request_validation`, schema errors on `items`, `beneficiary_due`, or `evidence` | A required field is missing from a multi-part body, common on Request pledge liquidation, which requires `reference`, `reason`, `beneficiary_due`, `items`, and `evidence` together. | Check the `fields` object in the error response against the endpoint's required body parameters. |
# Create Your First Quote
Source: https://docs.busha.io/guides/quotes/create-first-quote
Learn how to create quotes in Busha. Lock in exchange rates and fees before executing transactions.
This guide will walk you through the essential first step of almost any transaction on Busha: creating a Quote. By generating a Quote, you lock in the terms of a proposed asset transfer, ensuring price certainty and transparency before committing to the transaction.
**What You'll Achieve:**
1. Understand the basic structure for requesting a Quote.
2. Successfully generate a Quote for a currency conversion.
3. Learn how to use source\_amount vs target\_amount in your requests.
4. Explore how to include optional `pay_in` and `pay_out` details in your Quote requests.
5. Interpret a successful Quote response.
## Prerequisites
Before you begin, ensure you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
* A conceptual understanding of Quotes (from the [Quotes explainer](../../overview/quotes)).
For deposit requests involving a customer, the `X-BU-PROFILE-ID` field should
be included in the request header, and its value should be set to the customer
ID for whom the request is performed on their behalf.
## How to Create Your First Quote
The core of creating a Quote involves specifying the currencies and the amount of the transfer. Remember, you must provide either the `source_amount` or `target_amount`, but not both.
The essential parameters for creating a quote are:
Parameter
Data Type
Required/Optional
Description
source\_currency
string
Required
The currency you're sending.
target\_currency
string
Required
The currency you're receiving.
source\_amount
string
Optional
The amount of source\_currency you want to send.
target\_amount
string
Optional
The amount of target\_currency you want to receive.
pay\_in
object
Optional
Details about the incoming transfer method.
pay\_out
object
Optional
Details about the outgoing transfer method.
Let's create a simple Quote for currency conversion (e.g., converting from NGN to BTC).
**To create a basic quote:**
1. Open your terminal or command prompt.
2. Use the `POST` request below to the `/v1/quotes` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL and `{YOUR SECRET_KEY}` with your actual key.
4. Choose either source\_amount or `target_amount`. In this example, we'll specify `source_amount`
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "NGN",
"target_currency": "BTC",
"source_amount": "200000"
}'
```
**Expected Response:**
A successful response will return a Quote object, providing the id for this quote, the calculated `target_amount`, the `rate`, `fees`, and the `expires_at` timestamp.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_AEv8vGiT4jvB",
"profile_id": "",
"source_currency": "NGN",
"target_currency": "BTC",
"source_amount": "200000",
"target_amount": "0.00118096",
"rate": {
"product": "BTCNGN",
"rate": "169353287.78",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "BTC"
},
"fees": [],
"reference": "QUO_AEv8vGiT4jvB",
"status": "pending",
"expires_at": "2025-06-10T08:37:56.721186819Z",
"created_at": "2025-06-10T08:07:26.721165473Z",
"updated_at": "2025-06-10T08:07:56.721165473Z"
}
}
```
1. Note the `id` of the Quote. You'll use this id to execute the transaction (e.g., conversion, deposit, or payout) in a subsequent step.
2. Check `expires_at`: Always ensure that the quote's `expires_at` time has not passed before attempting to use it.
While the quote creation process is the same across currencies, **payment methods differ by country**:
### Currency Specific Differences
Aspect
Nigeria (NGN)
Kenya (KES)
Currency
NGN (Naira)
KES (Kenyan Shilling)
Deposit Method
Bank transfer to business account
M-Pesa or mobile money
Payout Method
Bank transfer
M-Pesa or bank transfer
### Example: Creating a KES Quote
The API call structure is identical, just with different currency and amount:
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "50000",
"pay_in": {
"type": "mobile_money",
"phone": "+254712345678"
}
}'
```
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_KES123Example",
"source_currency": "KES",
"target_currency": "BTC",
"source_amount": "50000",
"target_amount": "0.00029123",
"rate": {
"product": "BTCKES",
"rate": "171680500.00",
"side": "buy",
"type": "FIXED",
"source_currency": "KES",
"target_currency": "BTC"
},
"fees": [],
"expires_at": "2025-06-10T08:37:56.721186819Z",
"created_at": "2025-06-10T08:07:26.721165473Z",
"updated_at": "2025-06-10T08:07:56.721165473Z"
}
}
```
For currency-specific payment method details, see:
* [Process Fiat Deposits](../deposits/process-fiat-deposits) for bank vs mobile money
* [Create Recipients](../recipients/create-and-manage) for payment method setup
For certain transaction types like deposits (PayIns) or direct crypto purchases, you might need to specify details about the incoming payment method using the `pay_in` object in your quote request. This helps Busha generate accurate deposit instructions.
**To create a quote for a deposit (e.g., crypto):**
1. Use a `POST` request to `/v1/quotes` as before.
2. Include the `pay_in` object with relevant details. For a crypto deposit, this might include the `network`.
```bash theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "BTC",
"target_currency": "NGN",
"target_amount": "50000",
"pay_in": {
"type": "address",
"network": "BTC"
}
}'
```
**Expected Response**
The Quote response itself will be similar to the basic one, with the `pay_in` object included in the response.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_mwdzbJiiAUa7",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.00029895",
"target_amount": "50000",
"rate": {
"product": "BTCNGN",
"rate": "167252998.89",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"network": "BTC",
"type": "address"
},
"reference": "QUO_mwdzbJiiAUa7",
"status": "pending",
"expires_at": "2025-06-10T08:46:54.461965014Z",
"created_at": "2025-06-10T08:16:54.461945463Z",
"updated_at": "2025-06-10T08:16:54.461945463Z"
}
}
```
When initiating a payout (withdrawal) from your Busha account, you'll need to specify details about the outgoing payment method using the `pay_out` object. This guides Busha on where and how to send the funds. This also typically requires a `recipient_id`.
**To create a quote for a payout**
For payouts to bank accounts, ensure you have a `recipient_id` for the bank
account you wish to pay out to. (Refer to: [How to Create and Manage
Recipients Guide](../recipients/create-and-manage))
1. Use a POST request to `/v1/quotes`.
2. Include the `pay_out` object with details for the target recipient and channel.
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/quotes \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"source_currency": "BTC",
"target_currency": "BTC",
"target_amount": "0.0001",
"pay_out": {
"type": "address",
"network": "BTC",
"address": "tb1qj4263506wyu8khrz2dwce0agk8lhyjgy269rxr"
}
}'
```
**Expected Response:**
The Quote response itself will be similar to the basic one, with the `pay_out` object included in the response.
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_0OF0pBoXllc0",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.0001",
"target_amount": "0.0001",
"rate": {
"product": "",
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [
{
"amount": {
"amount": "0.000005",
"currency": "BTC"
},
"name": "network fee",
"type": "FIXED"
}
],
"pay_out": {
"address": "tb1qj4263506wyu8khrz2dwce0agk8lhyjgy269rxr",
"network": "BTC",
"type": "address"
},
"reference": "QUO_0OF0pBoXllc0",
"status": "pending",
"created_at": "2025-06-10T08:35:34.224940272Z",
"updated_at": "2025-06-10T08:35:34.224940272Z"
}
}
```
## Troubleshooting Common Quote Creation Issues
* **"Quote expired"** in subsequent transactions: The quote ID you received was valid when created, but expired before you used it. Always generate a fresh quote immediately before executing the transaction.
* **"One of target and source amount must be set"**: You included both `source_amount` and `target_amount` in your request. Remove one.
* **`401 Unauthorized`**: Double-check that your secret API key is correct.
## What's Next?
Once you have successfully created a Quote, the next step is to execute the actual transaction based on that Quote.
* [How to Get a Quote](./get-quote)
* [How to Process Fiat Deposits (PayIns) Guide](../deposits/process-fiat-deposits)
* [How to Process Crypto Deposits (PayIns) Guide](../deposits/process-crypto-deposits)
* [How to Make Payouts Guide](../payouts/process-payouts)
* [How to Perform Currency Conversions Guide](../balance/convert-balance-to-balance)
* [API Reference: Quote Object](../../api-reference/quotes/create-a-new-quote): For a complete list of all parameters, sub-fields for `pay_in` and `pay_out`, and their data types.
# Retrieve a Quote
Source: https://docs.busha.io/guides/quotes/get-quote
Learn how to fetch and verify quote details. Check rates, fees, and expiration times.
After successfully creating a Quote, a unique id is returned in the API response. This Quote ID is essential for initializing and finalizing subsequent transfers. This guide will show you how to use this ID to retrieve the full details of any existing quote.
**What You'll Achieve:**
1. Understand why and when to retrieve quote information.
2. Successfully make an API request to fetch a specific quote.
3. Interpret the comprehensive Quote response, including pay\_in and pay\_out details.
## Prerequisites
Before you begin, ensure that you have:
* A Busha Business Account and Secret API Key (from the [Quick Start Tutorial](../getting-started/quick-start)).
* An understanding of API Environments (Sandbox vs. Production) and their base URLs (from the [Make Your First Request Guide](../getting-started/make-first-request)).
* A valid Quote ID from a previously created quote (e.g., `QUO_uNiw1CDqGrdIlK15N0bu1` from the [Creating A Quote Guide](./create-first-quote)).
For quote requests involving a customer, the X-BU-PROFILE-ID field should be
included in the request header, and its value should be set to the customer ID
for whom the request is performed on their behalf.
## How to Retrieve a Quote
To retrieve quote information, you'll use the GET method on the `/v1/quotes/{id}` endpoint. This endpoint allows you to query the state and details of a specific quote by providing its unique ID.
**Why retrieve a Quote?**
* **Check Expiration**: Verify if the quote is still valid before attempting to use it for a transaction.
* **Confirm Details:** Double-check source\_amount, target\_amount, rate, and fees.
* **Retrieve Transfer Instructions:** If the quote includes `pay_in` or `pay_out` details (e.g., a deposit address or bank details), you can retrieve them here to present to your users.
* **Monitor Status:** Although quotes typically stay *pending* until used or expired, checking its status can confirm its existence.
Use the GET request below, replacing the placeholders with your actual values.
**To retrieve quote information:**
1. Open your terminal or command prompt
2. Construct a GET request to the `/v1/quotes/{id}` endpoint.
3. Replace `YOUR_BASE_URL` with your chosen environment's URL (e.g., `https://api.sandbox.busha.so`).
4. Replace `{id}` with the actual ID of the quote you wish to retrieve (e.g., `QUO_uNiw1CDqGrdIlK15N0bu1`).
Replace `{YOUR_SECRET_API_KEY}` with your actual Secret API Key.
```bash theme={null}
$ curl --request GET \
--url YOUR_BASE_URL/v1/quotes/{id} \
--header 'Authorization: Bearer {YOUR_SECRET_API_KEY}' \
--header 'Content-Type: application/json'
```
Example:
```bash theme={null}
$ curl -i -X GET https://api.sandbox.busha.so/v1/quotes/QUO_AEv8vGiT4jvB \
-H 'Authorization: Bearer {YOUR_SECRET_API_KEY}' \
-H 'Content-Type: application/json'
```
Upon a successful request, the API will return the full Quote object, which is identical to the response you received when the quote was created.
**Expected Response:**
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_AEv8vGiT4jvB",
"profile_id": "",
"source_currency": "NGN",
"target_currency": "BTC",
"source_amount": "200000",
"target_amount": "0.00118096",
"rate": {
"product": "BTCNGN",
"rate": "169353287.78",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "BTC"
},
"fees": [],
"reference": "QUO_AEv8vGiT4jvB",
"status": "pending",
"expires_at": "2025-06-10T08:37:56.721186819Z",
"created_at": "2025-06-10T08:07:26.721165473Z",
"updated_at": "2025-06-10T08:07:56.721165473Z"
}
}
```
## Troubleshooting Common Issues:
* **404 Not Found**: The provided `{id}` does not correspond to an existing quote. Double-check the ID.
* **401 Unauthorized**: Ensure your Authorization: Bearer `{YOUR_SECRET_API_KEY}` header is correct and includes a valid API key.
* **Expired Quote**: If expires\_at is in the past, the quote cannot be used. You will need to create a new quote.
## What's Next?
Now that you know how to retrieve quote information, you can use this ID to proceed with your desired transaction:
* [Processing Fiat Deposits](../deposits/process-fiat-deposits)
* [Processing Crypto Deposits](../deposits/process-crypto-deposits)
* [Processing Payouts](../payouts/process-payouts)
* [Converting Balance Currencies](/guides/balance/convert-balance-to-balance)
* [API Reference: Get Quote by ID: For full details on the response fields](../../api-reference/quotes/get-quote).
# Create and Manage Recipients
Source: https://docs.busha.io/guides/recipients/create-and-manage
Set up payout recipients for bank accounts and mobile money. Manage recipient details and verification.
Recipients are pre-defined payment accounts (such as bank accounts, mobile money wallets, or crypto addresses) that act as destinations for your payouts via the Busha API. By creating and managing recipients, you streamline your off-ramp processes, ensuring funds are sent to verified and correct destinations quickly and efficiently.
**What You'll Achieve:**
1. Understand what recipients are and why they are necessary for payouts.
2. Learn how to dynamically fetch the required fields for creating a recipient based on country and currency.
## Prerequisites
Before you begin, ensure you have:
* A **Busha Business Account** and **Secret API Key** (from the [Quick Start Tutorial](/guides/getting-started/quick-start))
* An understanding of the **API Environments** (Sandbox vs. Production) and their respective base URLs (from the [Make Your First Request Guide](/guides/getting-started/make-first-request)).
## Recipient Types
Busha operates a multi-currency account system and accomodate recipients for each currency type. Currently, Busha supports the creation of recipients for:
* Nigerian bank accounts
* US bank accounts
* UK bank accounts
* M-Pesa mobile money (Kenya)
* MTN Mobile Money
* Cryptocurrency addresses
The recipient type is an important field in the request body object. Each recipient type have their unique fields outlined in the table below.
The recipient's request body varies from type to type. That is, the request body for a Nigerian bank account `ngn_bank`, will be different from that of a US bank account `usd_bank`.
In the following sections, we will create a recipient for each type and outline the required fields for each.
## Nigerian Bank Account
Nigerian bank account recipients require a `bank_code` field. You can retrieve your bank's code by sending a GET request to the `/banks` endpoint":
```shell theme={null}
$ curl -i -X GET https://api.sandbox.busha.so/v1/banks
```
The request body required to create a Nigerian bank account recipient is:
```json theme={null}
{
"currency": "NGN", // Recipient's bank currency
"country_code": "NG", // Recipient's country code
"type": "ngn_bank", // Recipient type
"bank_name": "OPAY", // Recipient's bank name
"bank_code": "100004", // Recipient's bank code
"account_number": "9000000000", // Recipient's account number
"account_name": "BUSHA DIGITAL TECHNOLOGY" // Recipient's account name
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `bank_name`
* `bank_code`
* `account_number`
* `account_name`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"currency": "NGN",
"country_code": "NG",
"type": "ngn_bank",
"bank_name": "OPAY",
"bank_code": "100004",
"account_number": "9000000000",
"account_name": "BUSHA DIGITAL TECHNOLOGY"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877ac708725d76db48eebff",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"account_name": "BUSHA DIGITAL TECHNOLOGY",
"account_number": "9169277397",
"active": true,
"bank_code": "100004",
"bank_name": "OPAY",
"category": "bank",
"country_code": "NG",
"currency": "NGN",
"object": "recipients",
"owned_by_customer": true,
"type": "ngn_bank"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## US Bank Account (ACH)
The request body required to create a US bank account (`usd_bank`) recipient with a transfer type `ach` is:
```json theme={null}
{
"type": "usd_bank", // Recipient type
"entity_type": "personal", // Recipient entity type
"transfer_type": "ach", // Recipient transfer type, ach
"account_name": "Jane Smith", // Recipient account name
"bank_name": "Chase Bank", // Recipient bank name
"routing_number": "021000021", // Recipient routing number
"account_number": "9876543210" // Recipient account number
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `entity_type` : This can be `personal` or `business` depending on the recipient's bank entity type.
* `account_number`
* `bank_name`
* `routing_number`
* `account_name`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "usd_bank",
"entity_type": "personal",
"transfer_type": "ach",
"account_name": "Jane Smith",
"bank_name": "Chase Bank",
"routing_number": "021000021",
"account_number": "9876543210"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877afc18725d76db48eec02",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"account_name": "Jane Smith",
"account_number": "9876543210",
"active": true,
"bank_name": "Chase Bank",
"category": "bank",
"country_code": "US",
"currency": "USD",
"entity_type": "personal",
"object": "recipients",
"owned_by_customer": true,
"routing_number": "021000021",
"transfer_type": "ach",
"type": "usd_bank"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## US Bank Account (Wire)
The request body required to create a US bank account (`usd_bank`) recipient with a transfer type `wire` is:
```json theme={null}
{
"type": "usd_bank", // Recipient type
"entity_type": "business", // Recipient entity type
"transfer_type": "wire", // Recipient transfer type, wire
"account_name": "Tech Corp LLC", // Recipient's account name
"bank_name": "Bank of America", // Recipient's bank name
"routing_number": "026009593", // Recipient's routing number
"account_number": "1122334455" // Recipient's account number
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `entity_type` : This can be `personal` or `business` depending on the recipient's bank entity type.
* `account_number`
* `bank_name`
* `routing_number`
* `account_name`
* `swift_code`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "usd_bank",
"entity_type": "business",
"transfer_type": "wire",
"account_name": "Tech Corp LLC",
"bank_name": "Bank of America",
"routing_number": "026009593",
"account_number": "1234567890",
"swift_code": "BOFAUS3N"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877b0a08725d76db48eec04",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"account_name": "Tech Corp LLC",
"account_number": "1234567890",
"active": true,
"bank_name": "Bank of America",
"category": "bank",
"country_code": "US",
"currency": "USD",
"entity_type": "business",
"object": "recipients",
"owned_by_customer": true,
"routing_number": "026009593",
"swift_code": "BOFAUS3N",
"transfer_type": "wire",
"type": "usd_bank"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## US Bank Account (SWIFT)
The request body required to create a US bank account (`usd_bank`) recipient with a transfer type of `swift` is:
```json theme={null}
{
"type": "usd_bank", // Recipient type
"entity_type": "business", // Recipient entity type
"transfer_type": "swift", // Recipient transfer type, swift
"account_name": "Global Corp Ltd", // Recipient's account name
"iban": "GB29NWBK60161331926819", // Recipient's IBAN
"swift_code": "CHASUS33XXX", // Recipient's SWIFT code
"bank_name": "Bank of International Transfers", // Recipient's bank name
"recipient_address": "123 Hauptstrasse, Berlin, 10115, Germany", // Recipient's address
"intermediary_bank_name": "Intermediary Global Bank", // Recipient's intermediary bank name
"intermediary_bank_address": "456 Avenue of Banks, Zurich", // Recipient's intermediary bank address
"intermediary_swift_code": "CHASUS33XXX" // Recipient's intermediary swift code
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `entity_type` : This can be `personal` or `business` depending on the recipient's bank entity type.
* `account_name`
* `iban`
* `swift_code`
* `bank_name`
* `recipient_address`
* `intermediary_bank_name`
* `intermediary_bank_address`
* `intermediary_swift_code`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "usd_bank",
"entity_type": "business",
"transfer_type": "swift",
"account_name": "Global Corp Ltd",
"iban": "GB29NWBK60161331926819",
"swift_code": "CHASUS33XXX",
"bank_name": "Bank of International Transfers",
"recipient_address": "123 Hauptstrasse, Berlin, 10115, Germany",
"intermediary_bank_name": "Intermediary Global Bank",
"intermediary_bank_address": "456 Avenue of Banks, Zurich",
"intermediary_swift_code": "CHASUS33XXX"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877bd038725d76db48eec0f",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"account_name": "Global Corp Ltd",
"active": true,
"bank_name": "Bank of International Transfers",
"category": "bank",
"country_code": "US",
"currency": "USD",
"entity_type": "business",
"iban": "GB29NWBK60161331926818",
"intermediary_bank_address": "456 Avenue of Banks, Zurich",
"intermediary_bank_name": "Intermediary Global Bank",
"intermediary_swift_code": "CHASUS33XXX",
"object": "recipients",
"owned_by_customer": true,
"recipient_address": "123 Hauptstrasse, Berlin, 10115, Germany",
"swift_code": "CHASUS33XXX",
"transfer_type": "swift",
"type": "usd_bank"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## M-Pesa Mobile Money
The request body required to create an M-Pesa mobile money (`mpesa_mobile_money`) recipient is:
```json theme={null}
{
"currency_id": "KES", // Currency ID
"country_id": "KE", // Country ID, Kenya
"type": "mpesa_mobile_money", // Recipient type
"phone_number": "+254712345678", // Recipient's phone number (Mobile money ID)
"account_name": "Samuel Kiprotich" // Recipient's account name
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `account_name`
* `phone_number`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "mpesa_mobile_money",
"account_name": "Samuel Kiprotich",
"phone_number": "+254712345678"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877b15d8725d76db48eec08",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"account_name": "Samuel Kiprotich",
"active": true,
"category": "mobile_money",
"country_code": "KE",
"currency": "KES",
"object": "recipients",
"owned_by_customer": true,
"phone_number": "+254712345678",
"type": "mpesa_mobile_money"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## Bitcoin
The request body required to create a cryptocurrency recipient on the Bitcoin network:
```json theme={null}
{
"type": "crypto", // Recipient type
"account_name": "Coco", // Recipient account name
"network": "BTC", // Recipient network
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh" // Recipient Bitcoin address
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `account_name` : The name to identify the Bitcoin address stored.
* `address`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "crypto",
"account_name": "Coco",
"network": "BTC",
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877bbf68725d76db48eec0d",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlw",
"category": "crypto",
"network": "BTC",
"object": "recipients",
"owned_by_customer": false,
"type": "crypto"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## USDT (ETH)
The request body required to create a cryptocurrency recipient (USDT) on the Ethereum network:
```json theme={null}
{
"type": "crypto", // Recipient type
"account_name": "Coco", // Recipient account name
"network": "ETH", // Recipient network
"address": "0x742d35Cc6543C4532f5D2b8d9a2b2A1234567881" // Recipient address
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `account_name` : The name to identify the USDT address stored.
* `address`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "crypto",
"account_name": "Coco",
"network": "ETH",
"address": "0x742d35Cc6543C4532f5D2b8d9a2b2A1234567881"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877ec5c985bb54f0f2f9543",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"address": "0x742d35Cc6543C4532f5D2b8d9a2b2A1234567881",
"category": "crypto",
"network": "ETH",
"object": "recipients",
"owned_by_customer": true,
"type": "crypto"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## STELLAR LUMENS
The request body required to create a cryptocurrency recipient on the XLM network:
```json theme={null}
{
"type": "crypto", // Recipient type
"account_name": "My Stellar Wallet", // Recipient's account name
"network": "XLM", // Recipient's network, XLM
"address": "GAHK7EEG2WWHVKDNT4CEQFZGKF2LGDSW2IVM4S5DP42RBW3K6BTODB4A", // Recipient's address
"memo": "123456789" // Recipient's memo
}
```
To create a recipient:
1. Open your terminal or command prompt.
2. Construct a `POST` request to the `/v1/recipients` endpoint.
3. In the request body, update the following fields with your recipient's details:
* `account_name` : The identifier for the recipient details.
* `address`
* `memo`
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN` with your actual details.
```shell theme={null}
$ curl -i -X POST \
https://YOUR_BASE_URL/v1/recipients \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "crypto",
"account_name": "My Stellar Wallet",
"network": "XLM",
"address": "GAHK7EEG2WWHVKDNT4CEQFZGKF2LGDSW2IVM4S5DP42RBW3K6BTODB4A",
"memo": "123456789"
}'
```
**Expected Response**
Upon successful creation, the API will return a response containing the details of the newly created recipient, including its unique `id`.
```json theme={null}
{
"status": "success",
"message": "Recipient created successfully",
"data": {
"id": "6877b18e8725d76db48eec0a",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"address": "GAHK7EEG2WWHVKDNT4CEQFZGKF2LGDSW2IVM4S5DP42RBW3K6BTODB4A",
"category": "crypto",
"memo": "123456789",
"network": "XLM",
"object": "recipients",
"owned_by_customer": true,
"type": "crypto"
}
}
```
This `id` is crucial and will be reused in several cases, especially when
making a payout into that specific payment account, as demonstrated in the
[How to Make Payouts Guide](/guides/payouts/process-payouts).
## Retrieve and List Recipients
After creating recipients, you'll often need to retrieve their details or get a list of all recipients associated with your profile. This allows you to manage your payout destinations and ensure you're using the correct `recipient_id` for transactions.
**Retrieve a Specific Recipient**
You can fetch the details of a single recipient if you know its unique `id`.
To retrieve a specific recipient:
1. Open your terminal or command prompt.
2. Construct a `GET` request to the `/v1/recipients/{id}` endpoint, replacing `{id}` with the actual recipient ID.
3. Ensure your `Authorization` and `YOUR_SECRET_TOKEN` headers are included.
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN`.
```bash theme={null}
$ curl -i -X GET \
'https://api.busha.co/v1/recipients/{id}' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'
```
**Expected Response:**
A successful response will return a single recipient object, identical in structure to the one received during creation, containing all its details.
```json theme={null}
{
"status": "success",
"message": "Recipient retrieved successfully",
"data": {
"id": "6877afc18725d76db48eec02",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"country_id": "US",
"created_at": "2025-07-16T13:57:21.150561Z",
"fields": [
{
"display_name": "currency",
"is_copyable": true,
"is_visible": false,
"name": "currency",
"required": false,
"value": "USD"
},
{
"display_name": "bank_name",
"is_copyable": true,
"is_visible": true,
"name": "bank_name",
"required": true,
"value": "Chase Bank"
},
{
"display_name": "entity_type",
"is_copyable": true,
"is_visible": true,
"name": "entity_type",
"required": true,
"value": "personal"
},
{
"display_name": "account_name",
"is_copyable": true,
"is_visible": true,
"name": "account_name",
"required": true,
"value": "Jane Smith"
},
{
"display_name": "country_code",
"is_copyable": true,
"is_visible": false,
"name": "country_code",
"required": false,
"value": "US"
},
{
"display_name": "transfer_type",
"is_copyable": true,
"is_visible": true,
"name": "transfer_type",
"required": true,
"value": "ach"
},
{
"display_name": "account_number",
"is_copyable": true,
"is_visible": true,
"name": "account_number",
"required": false,
"value": "9876543210"
},
{
"display_name": "routing_number",
"is_copyable": true,
"is_visible": true,
"name": "routing_number",
"required": false,
"value": "021000021"
}
],
"legal_entity_type": "personal",
"object": "recipients",
"owned_by_customer": true,
"type": "usd_bank",
"updated_at": "2025-07-16T13:57:21.150561Z",
"currency_id": "USD"
}
}
```
**List All Recipients**
To get an overview of all the recipients you have created, you can make a `GET` request to the `/v1/recipients` endpoint without specifying an ID.
To list all recipients:
1. Open your terminal or command prompt.
2. Construct a `GET` request to the `/v1/recipients` endpoint.
3. Ensure your `Authorization` header is included.
4. Replace placeholders like `YOUR_BASE_URL` and `YOUR_SECRET_TOKEN`.
```bash theme={null}
$ curl -i -X GET 'https://YOUR_BASE_URL/v1/recipients' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'
```
**Expected Response:**
A successful response will return a list (an array) of all recipient objects associated with your profile. This allows you to programmatically manage your available payout destinations.
```json theme={null}
{
"status": "success",
"message": "Recipients retrieved successfully",
"pagination": {
"current_entries_size": 10,
"next_cursor": "eyJhbmNob3IiOiIyMDI1LTA3LTE2VDEzOjU3OjIxLjE1MDU2MVoiLCJhbmNob3JfaWQiOiJjcmVhdGVkX2F0Iiwic2Vjb25kYXJ5X2FuY2hvcl9pZCI6ImlkIiwiZGlyZWN0aW9uIjoibmV4dCIsInBvc2l0aW9uIjowLCJzb3J0X29yZGVyIjoiZGVzYyIsImxpbWl0IjoxMH0="
},
"data": [
{
"id": "6877ec5c985bb54f0f2f9543",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"created_at": "2025-07-16T18:15:56.073128Z",
"fields": [
{
"display_name": "address",
"is_copyable": true,
"is_visible": true,
"name": "address",
"required": true,
"value": "0x742d35Cc6543C4532f5D2b8d9a2b2A1234567881"
},
{
"display_name": "network",
"is_copyable": true,
"is_visible": true,
"name": "network",
"required": true,
"value": "ETH"
}
],
"legal_entity_type": "personal",
"object": "recipients",
"owned_by_customer": true,
"type": "crypto",
"updated_at": "2025-07-16T18:15:56.073128Z"
},
{
"id": "6877e78e985bb54f0f2f9541",
"profile_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"user_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"active": true,
"country_id": "KE",
"created_at": "2025-07-16T17:55:26.935875Z",
"fields": [
{
"display_name": "currency",
"is_copyable": true,
"is_visible": false,
"name": "currency",
"required": false,
"value": "KES"
},
{
"display_name": "account_name",
"is_copyable": true,
"is_visible": true,
"name": "account_name",
"required": true,
"value": "Samuel Kiprotich"
},
{
"display_name": "country_code",
"is_copyable": true,
"is_visible": false,
"name": "country_code",
"required": false,
"value": "KE"
},
{
"display_name": "phone_number",
"is_copyable": true,
"is_visible": true,
"name": "phone_number",
"required": true,
"value": "+254712345678"
}
],
"legal_entity_type": "personal",
"object": "recipients",
"owned_by_customer": true,
"type": "mpesa_mobile_money",
"updated_at": "2025-07-16T17:55:26.935875Z",
"currency_id": "KES"
}
]
}
```
## What's Next?
Now that you know how to create, retrieve, and list recipients, you can use them in your transaction flows:
* [How to Process Payouts to Recipients](/guides/payouts/process-payouts)
* [The Recipient Object](/guides/reference/recipients)
* [Recipients API Reference](/api-reference/recipients/list-recipients): For full details on all available fields and endpoints
# Addresses, Banks, and Mobile Money
Source: https://docs.busha.io/guides/reference/addresses-banks-mobile
Reference for banks, mobile money providers, and crypto addresses in supported countries.
## Banks
We provide all available banks from our currently supported countries with the list of banks API. You can fetch all banks with a simple GET request:
```bash theme={null}
$ curl https://api.busha.co/v1/banks
```
A **bank account** is held by a bank or financial institution, allowing users to deposit, withdraw, and transfer funds. Bank accounts are integrated to facilitate **fiat currency transactions**, enabling users to move money between their traditional bank and their crypto wallet.
## Bank Account Verification for Payouts
* **Linking a Bank Account:** Users can add and verify their **local bank account** as a destination for payout.
Verify Bank Accounts with the resolve bank account endpoint before initiating a payout:
```bash theme={null}
$ curl https://api.busha.co/v1/recipients/resolve-bank-account \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"currency_id": "NGN",
"country_id": "NG",
"channel": "mobile_money",
"bank_code": "000013",
"account_number": "0123456789"
}'
```
## Addresses
Addresses functions like a bank account number but is specific to cryptocurrencies. Each blockchain network (Bitcoin, Ethereum, Solana, etc.) has its own format for crypto addresses.
For example:
* **Bitcoin (BTC) Address:** `bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf82t9`
* **Ethereum (ETH) Address:** `0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7`
### Generating Wallet Addresses:
* When a user creates an account on Busha, a unique crypto address is assigned to their wallet for each supported cryptocurrency.
* These addresses are generated using blockchain standards like **BIP-44** (for Bitcoin and similar assets) or **ERC-20** (for Ethereum-based tokens).
### Receiving Digital Tokens:
* Users can share their crypto address with others to receive payments or token transfers.
* The sender initiates a transaction by entering the recipient's **crypto address** in their wallet and confirming the transfer.
* The blockchain processes the transaction and updates the balance once confirmed.
### Verifying an Address for Payout:
To specify a cryptocurrency destination address when purchasing crypto via the Busha API, validate the address using a separate API request prior to the purchase transaction. This ensures the address is valid for the selected cryptocurrency and network.
```bash theme={null}
$ curl https://api.busha.co/v1/validate \
--request POST \
--header 'Accept: */*' \
--header 'Content-Type: application/json' \
--data '{
"type": "address",
"address": "tb1qj4263506wyu8khr22dwce0agk8lhyjgy269rxr",
"currency": "BTC",
"network": "BTC",
"memo": "memo"
}'
```
# Currency Pairs
Source: https://docs.busha.io/guides/reference/pairs
See available conversions between fiat and cryptocurrency.
Pairs in the Busha API represent the exchange rates between two currencies. This can be any of the following exchanges:
* Fiat-to-Fiat
* Fiat-to-Crypto
* Crypto-to-Crypto
Pairs resource allows you to anticipate the following about a currency pair:
* Current buy/sell price
* Minimum and maximum buy/sell amount
* Buy/sell supported
* Floating point decimal for the base and target currency
A single pair object looks like this:
```json theme={null}
{
"id": "ETHUSDT",
"base": "ETH",
"counter": "USDT",
"type": "crypto",
"buy_price": {
"amount": "2686.63",
"currency": "ETH"
},
"sell_price": {
"amount": "2686.58",
"currency": "USDT"
},
"is_buy_supported": true,
"is_sell_supported": true,
"min_buy_amount": {
"amount": "0.00447",
"currency": "ETH"
}
}
```
## List Pairs
To list all pairs, you can make an unauthenticated request to the Pairs endpoint:
```bash theme={null}
$ curl https://api.busha.co/v1/pairs
```
## Filter Pairs by Type
The pairs API allows filtering the list of pairs by type. The three allowed filter type values are:
* fiat
* crypto
* stablecoins
Here is an example of a filter by type:
```bash theme={null}
$ curl https://api.busha.co/v1/pairs?type=crypto
```
## Filter Pairs by Currency
You can also filter pairs by any of the supported currencies on the Busha API.
```bash theme={null}
$ curl https://api.busha.co/v1/pairs?currency=NGN
```
## Filter by Type and Currency
Combining the two examples above, you can filter for all fiat pairs type for NGN currency like so:
```bash theme={null}
$ curl https://api.busha.co/v1/pairs?currency=NGN&type=fiat
```
# Recipients Reference
Source: https://docs.busha.io/guides/reference/recipients
See the Recipient object.
The Recipient object represents a payment destination with a unified structure across all payment methods. Unused fields are returned as `null`.
ISO country code (NG, US, GB, KE, null for crypto)
type
string (enum)
Specific recipient type (see Types section)
category
string (enum)
General category: bank, mobile\_money,
crypto
entity\_type
string
Entity type: personal or business (nullable,
used for US/GB)
transfer\_type
string
Transfer method: ach, wire, swift
(nullable, used for US)
account\_name
string
Account holder name or wallet label (nullable)
bank\_name
string
Name of the bank (nullable)
bank\_code
string
Bank code (nullable, used for Nigeria)
sort\_code
string
Sort code (nullable, used for UK)
routing\_number
string
Routing number (nullable, used for US ACH/Wire)
swift\_code
string
SWIFT code (nullable, used for international transfers)
account\_number
string
Domestic account number (nullable)
iban
string
International account number (nullable, used for SWIFT)
phone\_number
string
Mobile money phone number (nullable)
network
string
Blockchain network (nullable, used for crypto)
crypto\_address
string
Wallet address (nullable, used for crypto)
memo
string
Memo/tag for crypto transfers (nullable)
recipient\_address
string
Recipient address for international transfers (nullable)
intermediary\_bank\_name
string
Intermediary bank name (nullable, used for SWIFT)
intermediary\_bank\_address
string
Intermediary bank address (nullable, used for SWIFT)
intermediary\_swift\_code
string
Intermediary bank SWIFT code (nullable, used for SWIFT)
# Supported Payment Channels
Source: https://docs.busha.io/guides/reference/supported-channels
View all supported payment methods. Bank transfers, mobile money, and cryptocurrency options.
## Deposit Channels
Asset Type
Channel Name
Description
Fiat
Bank Account
For depositing fiat currency (e.g., NGN) into your Busha fiat balance.
Fiat
Mobile Money
For depositing fiat currency (e.g., KES) via mobile money services.
Crypto
Crypto Address
For depositing cryptocurrencies directly into your Busha crypto wallets.
## Payout Channels
Asset Type
Channel Name
Description
Fiat
Bank Transfer
For withdrawing fiat currency (e.g., NGN) to an external bank account.
Fiat
Mobile Money
For withdrawing fiat currency (e.g., KES) to an external mobile money
wallet.
Crypto
Crypto Address
For withdrawing cryptocurrencies directly to an external crypto address.
## Supported Deposit Flow
Source
Destination
Supported
External Bank Account
Busha Fiat Balance
Yes
External Mobile Money
Busha Fiat Balance
Yes
External Crypto Wallet
Busha Crypto Wallet
Yes
## Supported Payout Flow
Source
Destination
Supported
Busha Fiat Balance
External Bank Account
Yes
Busha Crypto Wallet
External Crypto Wallet
Yes
Busha Fiat Balance
External Crypto Wallet
No
Busha Crypto Wallet
External Bank Account
Yes
# Supported Countries
Source: https://docs.busha.io/guides/reference/supported-countries
See which countries are supported by Busha Business.
Busha Business is available in 65 countries worldwide. Nigeria, Kenya, and the United States have full fiat payment and payout support. All other supported countries can transact using crypto.
You can retrieve the full list of supported countries and their available
payment and payout methods programmatically via `GET /v1/countries`.
## Nigeria
**Currency:** Nigerian Naira (NGN)
**Payment Methods**
* Temporary Virtual Bank
* Direct Debit
* Bank Transfer
**Payout Methods**
* Bank Transfer
***
## Kenya
**Currency:** Kenyan Shillings (KES)
**Payment Methods**
* Mobile Money
**Payout Methods**
* Mobile Money
***
## United States
**Currency:** US Dollars (USD)
**Payment Methods**
* USDT/USDC to USD
**Payout Methods**
* ACH Bank Transfer
* SWIFT
* Wire Transfer
***
## All Supported Countries
The following countries are supported for crypto transactions:
Andorra, Antigua and Barbuda, Argentina, Australia, Austria, Belgium, Benin,
Brazil, Bulgaria, Burundi, Canada, Chile, China, Colombia, Costa Rica, Croatia,
Czech Republic, Denmark, Estonia, Finland, France, Germany, Ghana, Greece,
Hong Kong, Hungary, Iceland, India, Indonesia, Ireland, Israel, Italy, Japan,
Luxembourg, Madagascar, Malta, Mauritius, Mexico, Mozambique, Namibia,
Netherlands, New Zealand, Norway, Philippines, Poland, Portugal, Qatar,
Romania, Rwanda, Saudi Arabia, Singapore, Slovakia, Slovenia, South Africa,
Spain, Sweden, Switzerland, Tanzania, United Arab Emirates, United Kingdom, Vietnam, Zambia
# Supported Currencies
Source: https://docs.busha.io/guides/reference/supported-currencies
Complete list of supported fiat and cryptocurrencies. NGN, KES, USDT, BTC, ETH, and more.
This section provides a categorized overview of the **fiat** and **cryptocurrencies** supported on the Busha platform, indicating their deposit, withdrawal, and ramp capabilities.
## Fiat Currencies
These are the traditional government-issued currencies that Busha supports for various operations.
Code
Name
Display Name
Deposit Supported
Withdrawal Supported
Ramp Buy Supported
Ramp Sell Supported
GHS
Cedi
GHS
Yes
Yes
No
No
KES
Shilling
KES
Yes
Yes
Yes
Yes
NGN
Naira
NGN
Yes
Yes
Yes
Yes
USD
US Dollar
USD
Yes
Yes
No
No
## Cryptocurrencies
These are digital currencies supported on the Busha platform.
### Further References
* **[API Reference: Retrieve a Specific Currency](/api-reference/currencies/retrieve-details-of-a-specific-currency)**
* **[API Reference: Retrieve a List of Supported Currencies](/api-reference/currencies/retrieve-supported-currencies)**
# Supported Industries
Source: https://docs.busha.io/guides/reference/supported-industries
See which business industries can use Busha.
This section provides a categorized overview of the business industries supported on the Busha platform, indicating their ID, name, description, category, and sector.
ID
Name
Description
Category
Sector
BIN\_Z1HpNXB9Q8jcHx4LzVp
Technology
Industry focused on technological advancements
IT
Tech
BIN\_A2StLXR3K2gjRj7JnqR
Healthcare
Industry related to health and medical services
Health
Medical
BIN\_C4UvTYR5V8jsOx5LmwQ
Education
Industry focused on learning and teaching
Academic
Education
BIN\_D5QsUYH7M8hrTx6KxyZ
Manufacturing
Industry for producing goods
Production
Industrial
BIN\_G8TvXYL0Q2jyIz9LwxN
Transportation
Industry focused on transport services
Logistics
Transport
BIN\_V1StGXR8Z5jdHi6BmyT
Other
BIN\_B3QtRYL6J9ksKs2MbtK
Financial services
Industry dealing with financial services
Banking
Financial
BIN\_H9UvZYL1R3kzJx0LuvO
Construction and Engineering
Industry for construction and building
Development
Construction
BIN\_F7SuWXJ9P1jxHz8LyzM
Hospitality and Tourism
Industry for services like hotels and restaurants
Services
Hospitality
BIN\_E6RtVZH8O9iuQy7LzuL
Retail and eCommerce
Industry related to retail and sales
Sales
Commerce
BIN\_E1IxOSA9J9jcHx4LzVs
Entertainment
Industry focused on entertainments
Media
Entertainment
BIN\_B3TuLXR3S2gjRj8JnsX
Government and Public Sector
Industry related to government and public administration
Government
Public Sector
BIN\_A3AtWYL6J9ssLs4AcxL
Creatives and Designs
Industry dealing with artistic and creative services
Creative Services
Arts & Design
BIN\_C2HpWZT9L8tqXq7KjA8L
Real Estate and Property Management
Industry dealing with buying, selling, and managing real estate
properties
Real Estate
Property & Construction
# Supported Transfer Types
Source: https://docs.busha.io/guides/reference/supported-transfers
View all available transfer types you can initiate with a quote.
The Quote resource is very powerful, it is used for many transfer operations on Busha. Here are the transfer types you can create with a Quote.
Source
Destination
Available On Quote
Transaction Type
External Bank Account
Busha Fiat Balance (e.g NGN, KES)
Yes
Deposit
External Crypto Address
Busha Fiat Balance (e.g NGN, KES)
Yes
Deposit
External Crypto Address
Busha Crypto Wallet
Yes
Deposit
External Bank Account
Busha Crypto Wallet
Yes
Buy (On-Ramp)
Busha Crypto Wallet
External Bank Account
Yes
Payout
Busha Crypto Wallet
External Wallet Address
Yes
Payout
Busha Crypto Wallet
Busha Crypto Wallet (different currency)
Yes
Conversion
Busha Fiat Balance
Busha Crypto Wallet
Yes
Buy Trade
Busha Crypto Wallet
Busha Fiat Balance
Yes
Sell Trade
# Test Addresses For Off-Ramp Operations
Source: https://docs.busha.io/guides/reference/test-addresses
Testnet assets for testing off-ramp operations in sandbox.
When testing off-ramp functionalities via API or Widget, you'll need testnet versions of cryptocurrencies. Here are common sources for obtaining them:
# Transfer Status
Source: https://docs.busha.io/guides/reference/transfer-status
Understand all transfer statuses on Busha.
Understanding the different statuses of your transfers on Busha can help you keep track of your funds. Here's a breakdown of what each status means:
## Core Transfer Statuses
**Pending:** Your transfer has been initiated, but we haven't received the funds yet. Think of this as the first step where you've told us about your transfer.
**Processing:** We've successfully received your funds, and they are now being actively handled. This means we're working on getting your transfer to its next stage.
**Cancelled:** The transfer has been cancelled and will not proceed. This could happen for various reasons, such as user cancellation or if the transfer couldn't be completed.
## Specific Transfer Statuses
**Funds Received** (`funds_received`): This status specifically indicates that we have successfully received your payment for a deposit. For a simple deposit into your Busha account, this is the final step.
**Funds Converted** (`funds_converted`): If your transfer involves currency conversion (e.g., Naira to USD), this status means the conversion has been successfully completed. For transfers that only involve a conversion, this is the final status.
**Outgoing Payment Sent** (`outgoing_payment_sent`): This status indicates that the payment for your transfer has been initiated and is currently being processed on our end, ready to be sent out.
**Funds Delivered** (`funds_delivered`): This is typically the final status for transfers that involve sending funds out (like a payout). It means the transfer is fully completed, and the funds have reached their destination.
## Transfer Completion Flow
Here's how different types of transfers typically conclude:
### Deposits
A deposit will typically stop at **Funds Received**.
Deposit Flow for Busha Transfer
### Conversions
A conversion will conclude with **Funds Converted** as its final status.
Conversion Flow from currency to currency
### Payouts
A payout or withdrawal will reach its final status at **Funds Delivered**.
Withdrawal Flow on Busha
# Request IDs
Source: https://docs.busha.io/guides/request-id/request-id
Track and troubleshoot API requests using unique request identifiers.
Every API request to Busha returns a unique request identifier in the response headers. Use request IDs to track specific API calls and expedite issue resolution when contacting Busha support.
## What is a Request ID?
A request ID is a unique identifier assigned to every API request. It helps both you and Busha support team pinpoint specific API calls for debugging and troubleshooting.
**Format:** `req_` followed by an alphanumeric string
**Example:** `req_JfPBXEC5rLHc`
**Validity:** Request IDs are available for 21 days after the request is made.
## How to Find the Request ID
The request ID is returned in the response headers of every API call under the `X-Request-Id` header.
### Example Request
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/balances \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-i
```
The `-i` flag includes response headers in the output.
### Example Response Headers
```
HTTP/1.1 200 OK
Date: Wed, 18 Feb 2026 13:29:10 GMT
Content-Type: application/json
X-Request-Id: req_JfPBXEC5rLHc
```
The request ID is: `req_JfPBXEC5rLHc`
## Viewing Request IDs in Code
```javascript Node.js theme={null}
const axios = require('axios');
try {
const response = await axios.get(
'https://api.sandbox.busha.so/v1/balances',
{
headers: { 'Authorization': 'Bearer YOUR_SECRET_KEY' }
}
);
// Get request ID from response headers
const requestId = response.headers['x-request-id'];
console.log('Request ID:', requestId);
} catch (error) {
// Also available in error responses
const requestId = error.response?.headers['x-request-id'];
console.error('Error Request ID:', requestId);
}
```
```python Python theme={null}
import requests
response = requests.get(
'https://api.sandbox.busha.so/v1/balances',
headers={'Authorization': 'Bearer YOUR_SECRET_KEY'}
)
# Get request ID from response headers
request_id = response.headers.get('X-Request-Id')
print(f'Request ID: {request_id}')
# Also available in error responses
try:
response = requests.post(...)
except requests.exceptions.RequestException as e:
request_id = e.response.headers.get('X-Request-Id')
print(f'Error Request ID: {request_id}')
```
```php PHP theme={null}
```
## When to Use Request IDs
### Reporting API Errors
When contacting Busha support about API issues, always include the request ID. This helps our team quickly locate the specific request in our logs.
**Example support message:**
> "I'm getting a 500 error when creating a quote. Request ID: `req_JfPBXEC5rLHc`"
### Debugging Failed Requests
If an API call fails or returns unexpected results, save the request ID along with your error logs for easier debugging.
```javascript theme={null}
// Log request ID with errors
catch (error) {
const requestId = error.response?.headers['x-request-id'];
logger.error({
message: 'Quote creation failed',
requestId: requestId,
error: error.message
});
}
```
### Tracking Specific Operations
For critical operations, store the request ID alongside the resource ID (e.g., transfer ID, quote ID) for complete audit trails.
```javascript theme={null}
const quoteResponse = await createQuote(params);
const requestId = quoteResponse.headers['x-request-id'];
// Store both IDs
await database.save({
quoteId: quoteResponse.data.id, // QUO_abc123
requestId: requestId, // req_xyz789
timestamp: new Date()
});
```
**21-Day Retention:** Request IDs are only available for 21 days. Don't rely on them for long-term auditing.
# Token Sharing
Source: https://docs.busha.io/guides/token-sharing/token-sharing
Share verified KYC data between platforms using Sumsub token sharing.
Share verified customer KYC data from partner platforms to streamline onboarding and eliminate duplicate verification processes.
## Overview
Token sharing enables seamless customer onboarding by accepting pre-verified KYC data from partner platforms through Sumsub. When a customer is already verified on a partner platform, you can import their verification data instead of requiring them to complete KYC again.
**How it works:**
1. Customer completes KYC verification on partner platform
2. Partner generates a Sumsub token containing the customer's verified data
3. Partner calls Busha's token-share endpoint with the token
4. Busha imports the verified KYC data
5. Customer is instantly verified without re-uploading documents
## Prerequisites
* A Busha Business Account and Secret API Key (from the [Quick Start Guide](/guides/getting-started/quick-start))
* Active Sumsub account with verified applicant
* Busha's Client ID
* Sumsub API credentials
## Setup
### Add Busha as Recipient
The Reusable KYC feature must be enabled on your Sumsub account before you can share tokens. Contact your Sumsub Customer Success Manager (CSM) to enable this feature if it is not already active.
Before sharing tokens, add Busha as a trusted recipient in your Sumsub dashboard:
1. Contact Busha support at [eng@busha.co](mailto:eng@busha.co) to receive a recipient token
2. Log into your Sumsub dashboard → Reusable Identity → Partners
3. Add Busha using the recipient token
## Generate Sumsub Token
Before sharing customer data with Busha, generate a share token from Sumsub. This token securely encapsulates the customer's verified KYC data.
Refer to [Sumsub's Generate Share Token documentation](https://docs.sumsub.com/reference/generate-share-token) for complete details on token generation.
### Request
```bash theme={null}
curl -X POST https://api.sumsub.com/resources/accessTokens/shareToken \
-H "Content-Type: application/json" \
-d '{
"applicantId": "63e092c51b7b4030f2e01154",
"forClientId": "BushaClientId",
"ttlInSecs": 600
}'
```
**Parameters:**
| Parameter | Type | Description |
| ------------- | ------ | ----------------------------------------------------- |
| `applicantId` | string | The Sumsub applicant ID of the verified customer |
| `forClientId` | string | Busha's unique identifier (provided by Busha support) |
| `ttlInSecs` | number | Token validity period in seconds (default: 600) |
**Authentication:** You'll need your Sumsub API credentials (App Token and Secret Key). See [Sumsub's authentication guide](https://docs.sumsub.com/reference/app-tokens) for authentication requirements.
**Busha's Client ID:** Contact Busha support at [eng@busha.co](mailto:eng@busha.co) to receive Busha's `forClientId` for token generation.
### Response
```json theme={null}
{
"token": "eyJhbGciOiJub25lIn0.eyJqdGkiOiJfYWN0LTZmODI2ZTU0LTE2MzctNDViMS05NzMyLWY1MjZiN2YxNWE3YyIsInVybCI6Imh0dHBzOi8vYXBpLnN1bXN1Yi5jb20ifQ.",
"forClientId": "BushaClientId"
}
```
Save the `token` value for the next step.
**Token Expiry:** Tokens expire based on `ttlInSecs`. Use the token immediately after generation.
**One-Time Use:** Each share token can only be used once. Generate a new token for each customer share.
**Token Format:** Treat the token as an opaque string. Do not parse or validate its contents, as the format may change.
## Share Token with Busha
Once you have the Sumsub token, share it with Busha to import the customer's verified data.
### Create Customer in Busha
First, create a customer record in Busha:
```bash theme={null}
$ curl -i -X POST https://YOUR_BASE_URL/v1/customers \
-H 'Authorization: Bearer {YOUR_SECRET_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer.example@gmail.com",
"has_accepted_terms": true,
"type": "individual",
"country_id": "NG",
"phone": "+234 8012345678",
"birth_date": "24-12-2000",
"address": {
"city": "Lagos",
"state": "Lagos",
"country_id": "NG",
"address_line_1": "10 Scranton Avenue",
"postal_code": "100001"
},
"first_name": "John",
"last_name": "Doe"
}'
```
**Response:**
```json theme={null}
{
"status": "success",
"message": "Created customer successfully",
"data": {
"address": {
"address_line_1": "10 Scranton Avenue",
"city": "Lagos",
"country_id": "NG",
"postal_code": "100001",
"state": "Lagos"
},
"business_id": "BUS_jlKUYwF9z1ynQZ98bWbaP",
"country_id": "NG",
"created_at": "2026-01-27T09:23:09.317273Z",
"deposit": true,
"display_currency": "NGN",
"email": "customer.example@gmail.com",
"first_name": "John",
"has_accepted_terms_of_service": true,
"id": "CUS_IL2Qf2pEoNADZ",
"last_name": "Doe",
"level": "0",
"payout": true,
"phone": "+234 8012345678",
"status": "inactive",
"type": "individual",
"updated_at": "2026-01-27T09:23:09.317273Z"
}
}
```
Save the `id` for the next step.
### Share the Token
Call Busha's token-share endpoint with the Sumsub token:
```bash theme={null}
curl -X POST https://api.sandbox.busha.so/v1/customers/CUS_abc123xyz/token-share \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJub25lIn0.eyJqdGkiOiJfYWN0LTZmODI2ZTU0LTE2MzctNDViMS05NzMyLWY1MjZiN2YxNWE3YyIsInVybCI6Imh0dHBzOi8vYXBpLnN1bXN1Yi5jb20ifQ."
}'
```
**Path Parameters:**
| Parameter | Type | Description |
| ------------- | ------ | ----------------------------------------- |
| `customer_id` | string | Busha customer ID (e.g., `CUS_abc123xyz`) |
**Body Parameters:**
| Parameter | Type | Description |
| --------- | ------ | ------------------------------------- |
| `token` | string | Sumsub share token from previous step |
**Response:**
```json theme={null}
{
"status": "success",
"message": "Customer token shared successfully"
}
```
### Verify Import
Check that the customer's verification status was updated:
```bash theme={null}
curl -X GET https://api.sandbox.busha.so/v1/customers/CUS_abc123xyz \
-H "Authorization: Bearer YOUR_SECRET_KEY"
```
The customer should now have updated `status` and `level` fields reflecting the imported KYC data.
## Integration Example
```javascript Node.js theme={null}
const axios = require('axios');
async function shareCustomerKYC(applicantId, customerEmail) {
// 1. Generate Sumsub share token
const sumsubResponse = await axios.post(
'https://api.sumsub.com/resources/accessTokens/shareToken',
{
applicantId: applicantId,
forClientId: 'BushaClientId',
ttlInSecs: 600
},
{
headers: {
'Content-Type': 'application/json',
'X-App-Token': process.env.SUMSUB_APP_TOKEN
}
}
);
const shareToken = sumsubResponse.data.token;
// 2. Create customer in Busha
const customerResponse = await axios.post(
'https://api.sandbox.busha.so/v1/customers',
{
email: customerEmail,
first_name: 'John',
last_name: 'Doe',
phone: '+234 8123456789',
type: 'individual',
country_id: 'NG'
},
{
headers: { 'Authorization': `Bearer ${process.env.BUSHA_SECRET_KEY}` }
}
);
const customerId = customerResponse.data.data.id;
// 3. Share token with Busha
await axios.post(
`https://api.sandbox.busha.so/v1/customers/${customerId}/token-share`,
{ token: shareToken },
{
headers: { 'Authorization': `Bearer ${process.env.BUSHA_SECRET_KEY}` }
}
);
// 4. Verify customer status
const verifiedCustomer = await axios.get(
`https://api.sandbox.busha.so/v1/customers/${customerId}`,
{
headers: { 'Authorization': `Bearer ${process.env.BUSHA_SECRET_KEY}` }
}
);
return verifiedCustomer.data.data;
}
// Usage
shareCustomerKYC('63e092c51b7b4030f2e01154', 'john@example.com')
.then(customer => console.log('Customer verified:', customer.status));
```
```python Python theme={null}
import requests
import os
def share_customer_kyc(applicant_id, customer_email):
# 1. Generate Sumsub share token
sumsub_response = requests.post(
'https://api.sumsub.com/resources/accessTokens/shareToken',
headers={
'Content-Type': 'application/json',
'X-App-Token': os.getenv('SUMSUB_APP_TOKEN')
},
json={
'applicantId': applicant_id,
'forClientId': 'BushaClientId',
'ttlInSecs': 600
}
)
share_token = sumsub_response.json()['token']
# 2. Create customer in Busha
customer_response = requests.post(
'https://api.sandbox.busha.so/v1/customers',
headers={'Authorization': f'Bearer {os.getenv("BUSHA_SECRET_KEY")}'},
json={
'email': customer_email,
'first_name': 'John',
'last_name': 'Doe',
'phone': '+234 8123456789',
'type': 'individual',
'country_id': 'NG'
}
)
customer_id = customer_response.json()['data']['id']
# 3. Share token with Busha
requests.post(
f'https://api.sandbox.busha.so/v1/customers/{customer_id}/token-share',
headers={'Authorization': f'Bearer {os.getenv("BUSHA_SECRET_KEY")}'},
json={'token': share_token}
)
# 4. Verify customer status
verified = requests.get(
f'https://api.sandbox.busha.so/v1/customers/{customer_id}',
headers={'Authorization': f'Bearer {os.getenv("BUSHA_SECRET_KEY")}'}
)
return verified.json()['data']
# Usage
customer = share_customer_kyc('63e092c51b7b4030f2e01154', 'john@example.com')
print(f"Customer verified: {customer['status']}")
```
## What's Next?
Now that you understand token sharing, you can explore related customer management topics:
* [Create Customer](/guides/customers/create-individual) - Learn how to create customers
* [Verify Identity](/guides/customers/verify-identity) - Manual verification process
* [Customer API Reference](/api-reference/customers) - Complete API documentation
# Set Up Webhooks
Source: https://docs.busha.io/guides/webhooks/setup
Configure webhooks to receive real-time notifications. Monitor deposits, payouts, and transaction status.
When you make a transfer request, you typically have to wait for a payment to be sent into/out of the platform before that transfer can be updated as done. This can be achieved by either polling the GET Transfer API or by listening to a webhook URL.
A webhook URL is simply a POST endpoint that the Busha API server sends updates to. The URL needs to receive and parse a JSON request and return a 200 OK response.
Webhook is the recommended way to listen for updates for a transfer request as
the polling alternative will not be reliable due to poor connection on the
client side, which you do not have control over.
## Prerequisites
Before you start, make sure you have:
* A Busha Business Account (from the [Quick Start Guide](/guides/getting-started/quick-start)).
## How to setup Webhooks
Before you can receive webhook events from Busha, you need a dedicated URL where these events will be sent. This URL acts as the listener for all notifications your application needs to process. You have two primary options for setting up this endpoint:
**For Production Environments (Your Application)**
For a live, robust integration, you will need to create a specific endpoint within your own application's backend. This endpoint should be:
* **Publicly Accessible:** It must be a live URL that Busha's servers can reach over the internet (e.g., `https://your-domain.com/busha-webhook`). Localhost URLs will not work.
* **Configured to Receive POST Requests:** Your endpoint should be designed to listen for and process incoming HTTP POST requests, as this is how Busha will deliver webhook payloads.
* **Designed for Processing:** This endpoint should contain the logic to verify the webhook signature (for security) and then process the event data according to your application's needs.
**For Testing and Development (e.g., [Webhook.site](https://webhook.site))**
If you are just getting started, testing your integration, or inspecting webhook payloads, you can use a temporary third-party service to generate a quick webhook URL:
* **Using Webhook.site:** Navigate to [webhook.site](https://webhook.site). The site will instantly provide you with a unique, temporary URL.
* **Functionality:** Any POST requests sent to this URL will be immediately displayed on the page, allowing you to inspect the payload, headers, and other details.
**Important Note:** URLs generated by services like Webhook.site are for testing and development purposes only and should never be used in a production environment due to their temporary nature and lack of security controls.
After you have created your webhook URL, you need to visit the developer tools section on your dashboard to register the URL. **Settings > Developer Tools > Webhooks**
Click on the "Create a new Webhook" button. You should see an input form like this:
Enter a name for your webhook and include the full path to the webhook URL you created in the previous step then select the events you want to subscribe to, click on the "Create webhook" button, then copy your secret key.
Ensure to copy your Webhook Secret Key and truly keep it secret. This secret
is important and will be used to validate that every request made to your
webhook URL is genuinely from Busha.
**Verifying Webhook Signature**
To calculate and verify the `x-bu-signature`, perform a HMAC hash of the request body using the Webhook secret as the key.
For example:
```go theme={null}
func ValidateHMACChecksum(body []byte, checksum string) (bool, error) {
mac := hmac.New(sha256.New, []byte(hmacSecret))
mac.Write(body)
expectedMAC := mac.Sum(nil)
actualMAC, err := base64.StdEncoding.DecodeString(checksum)
if err != nil {
return false, fmt.Errorf("failed to decode checksum: %w", err)
}
return hmac.Equal(actualMAC, expectedMAC), nil
}
```
**Webhooks receive the following events from Busha:**
Event Types
Description
transfer.pending
A new Transfer has been initiated and is pending
transfer.processing
A transfer is processing.
transfer.cancelled
A transfer has been cancelled by the user.
transfer.funds\_received
A deposit transfer has been received successfully.
transfer.funds\_converted
An internal conversion transfer has been completed
transfer.outgoing\_payment\_sent
A payout transfer to a recipient or external wallet address has been
sent to the beneficiary and awaiting confirmation of receipt.
transfer.funds\_delivered
A payout transfer has been confirmed as received by the beneficiary
successfully.
**Sample Event Payload:**
```json theme={null}
{
"business_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"event": "transfer.funds_converted",
"data": {
"id": "TRF_BaAUvCTlZCt3hu3OO4u8P",
"profile_id": "BUS_tg6yujbZ1nMu5BLQkPGGO",
"quote_id": "QUO_5CnpikeQJEKQoDcnOsdkU",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "10000",
"target_amount": "5.728032",
"rate": {
"product": "USDTNGN",
"rate": "1745.8",
"side": "buy",
"type": "FIXED",
"source_currency": "NGN",
"target_currency": "USDT"
},
"fees": [],
"status": "completed",
"created_at": "2025-02-21T09:55:20.852345Z",
"updated_at": "2025-02-21T09:55:22.365451Z"
}
}
```
## Transfer Status Development
The following section aims to show how a transfer can develop from one status to another. This will show you understand how to properly handle and anticipate webhook events.
**Transfer.Pending:**
This is the initial status for all transfers. All transfers start as pending, and a pending transfer can morph into only two next statuses:
* transfer.cancelled
* transfer.processing
**Transfer.Cancelled:**
A cancelled transfer means that the transfer was unable to continue and can not begin processing. Hence, this is a final state that can not further change.
**Transfer.Processing:**
A processing transfer means that the transfer has started work and is already making the money movement from the destination to the source. A processing transfer can change into any of these statuses depending on the transfer type:
* transfer.outgoing\_payment\_sent
* transfer.funds\_received
* transfer.funds\_converted
**Transfer.OutgoingPaymentSent:**
An `outgoing_payment_sent` status represents any transfer that involves sending money out of the Busha platform to an external bank account or an external wallet address. It is not a final status; the outgoing\_payment\_sent status can morph into a final `funds_delivered` status
**Funds.Delivered:**
This is a final status that communicates that a payout transfer has been delivered successfully to the specified destination.
**Funds.Received:**
The `funds_received` status communicates that a Deposit into a Busha Balance has been successful. This could be a final status for all deposit transfers; however, in a scenario where the source currency is not the same as the target currency, then this transfer will further change into a `funds_converted` status.
**Funds.Converted:**
The `funds_converted` status communicates that a conversion transfer has been done successfully. This is also the same status that communicated the successful Buy/Sell Trade.
## Transfer Status Change Map
**Conversions and Trades(Buy/Sell) Status Change:**
```
pending → processing → funds_converted
```
**Payouts Status Change:**
```
pending → processing → outgoing_payment_sent → funds_delivered
```
**Deposit Status Change:**
```
pending → processing → funds_received
```
**On-Ramp (External Fiat → Crypto):**
```
pending → processing → funds_received → funds_converted
```
**On-Ramp (External Fiat → External Wallet):**
```
pending → processing → funds_received → funds_converted → outgoing_payment_sent → funds_delivered
```
# Webhook Events
Source: https://docs.busha.io/guides/webhooks/webhook-events
Real-time notifications for transfers, deposits, conversions, payouts, payment requests, and customer verification in your Busha integration.
Busha sends webhook notifications to your server when events happen on your account. Use webhooks to automate workflows and keep your application in sync with Busha.
## Why Use Webhooks?
Webhooks eliminate the need to poll the API repeatedly instead, Busha notifies you instantly when something happens.
**Common use cases:**
* Confirm order fulfillment after payment
* Update order status in your database
* Send customer receipts automatically
* Trigger inventory updates
* Notify customers of payment status
* Automate customer verification workflows
***
## Customer Events
Customer events track the lifecycle of customer accounts, including creation, updates, and verification status changes.
### customer.created
**Sent when:** A new customer account is created.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.created",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "inactive",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z"
}
}
```
***
### customer.updated
**Sent when:** Customer account information is updated (e.g., address, phone number, documents).
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.updated",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"phone": "+234 8087654321",
"type": "individual",
"status": "inactive",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T09:25:15.123456Z"
}
}
```
***
### customer.verification.in\_review
**Sent when:** Customer verification documents have been submitted and are under review.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.verification.in_review",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "in_review",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T09:26:34.537881Z"
}
}
```
***
### customer.verification.active
**Sent when:** Customer verification has been approved and the account is now active.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.verification.active",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "active",
"level": "1",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T10:15:20.456789Z"
}
}
```
***
### customer.verification.rejected
**Sent when:** Customer verification has been rejected due to invalid or incomplete documents.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.verification.rejected",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "rejected",
"level": "0",
"rejection_reason": "Invalid identification documents provided",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T10:30:45.789012Z"
}
}
```
***
### customer.verification.inactive
**Sent when:** Customer verification status has been reverted to inactive (e.g., due to compliance issues or account suspension).
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "customer.verification.inactive",
"data": {
"id": "CUS_Ikdb49NLsnlYU",
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"business_name": "",
"first_name": "John",
"last_name": "Doe",
"email": "customer@gmail.com",
"type": "individual",
"status": "inactive",
"level": "0",
"created_at": "2026-01-27T09:23:09.317273Z",
"updated_at": "2026-01-27T11:00:00.123456Z"
}
}
```
***
## Transfer Events
Transfer events track the complete lifecycle of all fund movements on Busha, including:
* **Deposits** - Receiving crypto or fiat into your Busha account
* **Conversions** - Converting between currencies (crypto-to-fiat, fiat-to-crypto, crypto-to-crypto)
* **Payouts** - Sending funds to bank accounts or external wallets
### transfer.pending
**Sent when:** A new transfer is created and awaiting funds.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.pending",
"data": {
"id": "TRF_HGjjAUDo1pti",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_0qoz7fXtHRFd",
"description": "Sold BTC",
"sub_description": "For NGN",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.00036606",
"target_amount": "50001.27",
"trade": "sell",
"rate": {
"product": "BTCNGN",
"rate": "136593125.15",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"fees": [],
"pay_in": {
"address": "tb1qnltjz527u6pxvcavqwrrja6znyrgd9c2pcl7qu",
"expires_at": "2025-12-10T11:35:59.175239Z",
"network": "BTC",
"type": "address"
},
"status": "pending",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-12-10T10:35:59.108130515Z",
"updated_at": "2025-12-10T10:35:59.108130584Z"
}
}
```
***
### transfer.processing
**Sent when:** Funds have been received and are being actively processed.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.processing",
"data": {
"id": "TRF_Bz6i6C5HaS7t",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.0001841",
"target_amount": "25000.17",
"status": "processing",
"created_at": "2025-12-05T13:12:57.582284Z",
"updated_at": "2025-12-05T13:13:30.123456Z"
}
}
```
***
### transfer.funds\_received
**Sent when:** Funds have been successfully received into your Busha account. This is an intermediate status before conversion.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.funds_received",
"data": {
"id": "TRF_5Vel81eg7kuz",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_K7viFhMDuYE4",
"description": "Bought BTC",
"sub_description": "With USDT",
"source_currency": "USDT",
"target_currency": "BTC",
"source_amount": "16.80378556",
"target_amount": "0.00018",
"trade": "buy",
"rate": {
"product": "BTCUSDT",
"rate": "90825.65",
"side": "buy",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "BTC"
},
"fees": [],
"pay_in": {
"address": "0x28730e094b58cb4e8B57549fC451aaB3423Ba4B7",
"expires_at": "2025-12-05T14:31:33.610518Z",
"network": "BSC",
"type": "address",
"blockchain_hash": "busha_579b948e43caf0f89c4edfc4572425a38564ac708b9bfba177bd395d49076c53",
"blockchain_url": "https://testnet-explorer.binance.org/tx/busha_579b948e43caf0f89c4edfc4572425a38564ac708b9bfba177bd395d49076c53",
"from_address": "busha/groot/USDT/PYT_FpqPiXPvLa6T"
},
"status": "funds_received",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-12-05T13:31:33.537625Z",
"updated_at": "2025-12-05T13:32:42.685331Z"
}
}
```
***
### transfer.funds\_converted
**Sent when:** Currency conversion is complete (crypto-to-fiat, fiat-to-crypto, or crypto-to-crypto). This is the final status for conversion transfers.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.funds_converted",
"data": {
"id": "TRF_5Vel81eg7kuz",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_K7viFhMDuYE4",
"description": "Bought BTC",
"sub_description": "With USDT",
"source_currency": "USDT",
"target_currency": "BTC",
"source_amount": "16.80378556",
"target_amount": "0.00018",
"trade": "buy",
"rate": {
"product": "BTCUSDT",
"rate": "90825.65",
"side": "buy",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "BTC"
},
"fees": [],
"pay_in": {
"address": "0x28730e094b58cb4e8B57549fC451aaB3423Ba4B7",
"expires_at": "2025-12-05T14:31:33.610518Z",
"network": "BSC",
"type": "address",
"blockchain_hash": "busha_579b948e43caf0f89c4edfc4572425a38564ac708b9bfba177bd395d49076c53",
"blockchain_url": "https://testnet-explorer.binance.org/tx/busha_579b948e43caf0f89c4edfc4572425a38564ac708b9bfba177bd395d49076c53",
"from_address": "busha/groot/USDT/PYT_FpqPiXPvLa6T"
},
"status": "funds_converted",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2025-12-05T13:31:33.537625Z",
"updated_at": "2025-12-05T13:32:42.836738Z"
}
}
```
***
### transfer.completed
**Sent when:** Transfer has been successfully completed. This is the final status for successful transfers.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.completed",
"data": {
"id": "TRF_Bz6i6C5HaS7t",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"quote_id": "QUO_yPfvBpxstyjp",
"description": "Sold BTC",
"sub_description": "For NGN",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.0001841",
"target_amount": "25000.17",
"trade": "sell",
"rate": {
"product": "BTCNGN",
"rate": "135796707.37",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"fees": [],
"status": "completed",
"timeline": {
"total_steps": 2,
"current_step": 2,
"transfer_status": "completed",
"events": [
{
"step": 1,
"done": true,
"status": "funds_received",
"title": "Crypto Received",
"description": "Funded from Balance"
},
{
"step": 2,
"done": true,
"status": "completed",
"title": "Transfer Completed",
"description": "Funds have been successfully processed"
}
]
},
"created_at": "2025-12-05T13:12:57.582284Z",
"updated_at": "2025-12-05T13:14:38.243849Z"
}
}
```
***
### transfer.failed
**Sent when:** Transfer fails due to an error (insufficient funds, network issues, invalid recipient details, etc.).
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.failed",
"data": {
"id": "TRF_failed123",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.0001",
"target_amount": "15000",
"status": "failed",
"error": {
"code": "insufficient_funds",
"message": "Insufficient balance to complete transfer"
},
"created_at": "2025-12-05T10:00:00.000000Z",
"updated_at": "2025-12-05T10:05:00.000000Z"
}
}
```
***
### transfer.cancelled
**Sent when:** Transfer is cancelled (due to user cancellation or system cancellation).
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.cancelled",
"data": {
"id": "TRF_aKn8Z3Cmtc8a",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "USDC",
"target_currency": "NGN",
"source_amount": "16.91200347",
"target_amount": "25000",
"status": "cancelled",
"created_at": "2025-12-04T12:06:47.648775Z",
"updated_at": "2025-12-04T12:36:47.648775Z"
}
}
```
***
### transfer.funds\_not\_delivered
**Sent when:** Funds were received but could not be delivered to the final destination (e.g., invalid bank account, network issues during payout).
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "transfer.funds_not_delivered",
"data": {
"id": "TRF_notDelivered789",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"source_currency": "NGN",
"target_currency": "NGN",
"source_amount": "5000",
"target_amount": "5000",
"status": "funds_not_delivered",
"pay_out": {
"type": "bank_transfer",
"recipient_details": {
"account_name": "John Doe",
"account_number": "0123456789",
"bank_name": "First Bank of Nigeria"
}
},
"error": {
"code": "invalid_account",
"message": "Bank account details are invalid or account is closed"
},
"created_at": "2025-12-05T14:20:00.000000Z",
"updated_at": "2025-12-05T14:25:00.000000Z"
}
}
```
***
### transfer.funds\_refunded
**Sent when:** Funds are refunded to the balance following a failed transfer.
```json theme={null}
{
"business_id": "BUS_5XUsDLKxHTapLHMhlMmcM",
"event": "transfer.funds_refunded",
"data": {
"id": "TRF_X0YjV4Z36JW3",
"profile_id": "BUS_5XUsDLKxHTapLHMhlMmcM",
"quote_id": "QUO_9sxWKHbsJEJ2",
"description": "Sold BTC",
"sub_description": "For BTC",
"source_currency": "BTC",
"target_currency": "BTC",
"source_amount": "0.000075",
"target_amount": "0.00007",
"rate": {
"rate": "1",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "BTC"
},
"fees": [
{
"amount": {
"amount": "0.000005",
"currency": "BTC"
},
"name": "network fee",
"type": "FIXED"
}
],
"pay_out": {
"address": "tb1ql8xvg2adnt0j5vxzgg7n00zmaf4y65wegpvzcl",
"network": "BTC",
"type": "address"
},
"status": "funds_refunded",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-02-03T15:01:20.239458Z",
"updated_at": "2026-02-03T15:07:36.608114Z"
}
}
```
***
### transfer.funds\_delivered
**Sent when:** Funds have been successfully delivered to the final destination (e.g., bank account or external wallet).
```json theme={null}
{
"business_id": "BUS_5asfnvrY9UuXBun4GWqNW",
"event": "transfer.funds_delivered",
"data": {
"id": "TRF_BuIVXa89aFC3",
"profile_id": "BUS_5asfnvrY9UuXBun4GWqNW",
"quote_id": "QUO_VJOBEK5ycGVM",
"stages": [
"conversion",
"withdrawal"
],
"category": "sell",
"description": "Sold USDC",
"sub_description": "For NGN",
"source_currency": "USDC",
"target_currency": "NGN",
"source_amount": "0.4430943",
"target_amount": "500",
"trade": "sell",
"rate": {
"product": "USDCNGN",
"rate": "1371.04",
"side": "sell",
"type": "FIXED",
"source_currency": "USDC",
"target_currency": "NGN"
},
"fees": [
{
"amount": {
"amount": "100",
"currency": "NGN"
},
"name": "Fees",
"type": "FIXED"
},
{
"amount": {
"amount": "7.5",
"currency": "NGN"
},
"name": "VAT on Fee (7.5%)",
"type": "FIXED"
}
],
"pay_out": {
"recipient_details": {
"account_name": "ABDULAZEEZ ABDULAZEEZ ADESHIN",
"account_number": "0453699151",
"bank_code": "000013",
"bank_name": "Guaranty Trust Bank"
},
"recipient_id": "68cbd12c0dd5c496d6fcb181",
"type": "bank_transfer",
"session_id": "090405260508143512664405513864"
},
"status": "funds_delivered",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"created_at": "2026-05-08T13:33:52.23489Z",
"updated_at": "2026-05-08T13:35:14.54597Z"
}
}
```
***
## Deposit Events
Deposit events track incoming funds to your Busha account from fiat or crypto sources.
### deposit.success
**Sent when:** Funds are successfully deposited to your Busha account (fiat via bank transfer or crypto via wallet).
**Use case:** Automatically convert deposits to your preferred currency using the Quotes and Transfers endpoints. For example, convert incoming fiat deposits to stablecoin or vice versa.
```json theme={null}
{
"business_id": "bus_1a2b3c4d5e6f7g8h9i0j",
"event": "deposit.success",
"data": {
"id": "289bb2c1-b4fc-46df-b313-6945a8d23615",
"profile_id": "CUS_9z8y7x6w5v4u3t2s1r",
"amount": "5900.00",
"fee": "100.00",
"total": "6000.00",
"currency": "NGN",
"reference": "Resf12dx3c333333",
"channel": "bank_transfer",
"status": "COMPLETED",
"source_account_name": "Test Oluwatoni",
"source_bank_name": "Bank of World",
"source_account_number": "1234567890",
"reserved_account_id": "8d1c58b0-9143-410b-be61-805e8421c466",
"account_name": "ARTAX DIGITAL / Oluwatoni Test",
"account_number": "4051483002",
"created_at": "2025-02-26T11:29:02.336285+01:00"
}
}
```
**Key fields:**
* `amount`: The deposited amount (after fees)
* `fee`: The deposit fee charged
* `total`: The total amount deposited (before fees)
* `currency`: The currency of the deposit (e.g., NGN, KES)
* `status`: Deposit status (COMPLETED)
* `profile_id`: The customer ID who made the deposit
* `reference`: Unique deposit reference for reconciliation
* `channel`: The method of deposit (e.g., bank\_transfer)
***
## Payment Request Events
Payment request events track the lifecycle of payment links created through the Busha Business API. These are typically used for e-commerce integrations, invoicing, and customer payment flows.
### payment\_request.pending
**Sent when:** Payment request is awaiting customer payment.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.pending",
"data": {
"id": "PAYR_oIPbFOXogbjW",
"additional_info": {
"email": "ajibola@busha.co",
"name": "Jibola Obi",
"phone_number": "",
"source": ""
},
"created_at": "2025-12-10T10:35:59.220244444Z",
"expires_at": "2025-12-10T11:35:59.175239Z",
"fees": [],
"merchant_info": {
"email": "ajibola@busha.co",
"name": "Liverppol"
},
"pay_in": {
"address": "tb1qnltjz527u6pxvcavqwrrja6znyrgd9c2pcl7qu",
"expires_at": "2025-12-10T11:35:59.175239Z",
"network": "BTC",
"type": "address"
},
"rate": {
"product": "BTCNGN",
"rate": "136593125.15",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"reference": "PAYR_oIPbFOXogbjW",
"source_amount": "0.00036606",
"status": "pending",
"target_amount": "50001.27",
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"updated_at": "2025-12-10T10:35:59.220244497Z",
"source_currency": "BTC",
"target_currency": "NGN"
}
}
```
***
### payment\_request.processing
**Sent when:** Payment has been received and is being processed.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.processing",
"data": {
"id": "PAYR_NwSBgvVszPvA",
"additional_info": {
"email": "ajibola@busha.co",
"name": "Jibola Obi",
"phone_number": "+2348012345678",
"source": "checkout_page"
},
"created_at": "2025-12-09T09:51:03.422936437Z",
"merchant_info": {
"email": "ajibola@busha.co",
"name": "Liverpool"
},
"pay_in": {
"address": "GDHHXPUSZK2OYHEVAP7GG6MTDWY2VQ4V5JBTIKFEV526RT6QYF23BSXD",
"network": "XLM",
"type": "address",
"blockchain_hash": "abc123def456...",
"blockchain_url": "https://stellarchain.io/tx/abc123def456..."
},
"reference": "PAYR_NwSBgvVszPvA",
"source": "payment_link",
"source_amount": "6.76480139",
"source_id": "58HgbtNDA34Z",
"status": "processing",
"target_amount": "10000",
"source_currency": "USDC",
"target_currency": "NGN",
"updated_at": "2025-12-09T10:10:30.123456Z"
}
}
```
***
### payment\_request.completed
**Sent when:** Customer successfully completes payment via payment link.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.completed",
"data": {
"id": "PAYR_InpIYLNIivEr",
"additional_info": {
"email": "ajibola@busha.co",
"name": "Jibola Obiwole",
"phone_number": "",
"source": ""
},
"created_at": "2025-12-05T13:28:02.698909Z",
"expires_at": "2025-12-05T14:28:02.611403Z",
"fees": [],
"merchant_info": {
"email": "ajibola@busha.co",
"name": "Liverppol"
},
"pay_in": {
"address": "0x817e43857CBFdCf48F2b35E86570031E46D8Db11",
"expires_at": "2025-12-05T14:28:02.611403Z",
"network": "BSC",
"type": "address"
},
"rate": {
"product": "USDTNGN",
"rate": "1487.76",
"side": "sell",
"type": "FIXED",
"source_currency": "USDT",
"target_currency": "NGN"
},
"reference": "PAYR_InpIYLNIivEr",
"source_amount": "16.80378556",
"status": "completed",
"target_amount": "25000",
"timeline": {
"total_steps": 3,
"current_step": 3,
"transfer_status": "funds_converted",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your USDT deposit",
"timestamp": "2025-12-05T13:29:00.723079Z"
},
{
"step": 2,
"done": true,
"status": "funds_received",
"title": "Crypto Received",
"description": "We received your USDT Deposit",
"timestamp": "2025-12-05T13:29:00.723079Z"
},
{
"step": 3,
"done": true,
"status": "funds_converted",
"title": "Funds Converted",
"description": "Money has been added to your wallet.",
"timestamp": "2025-12-05T13:29:00.853277Z"
}
]
},
"updated_at": "2025-12-05T13:29:01.974712Z",
"source_currency": "USDT",
"target_currency": "NGN"
}
}
```
***
### payment\_request.expired
**Sent when:** Payment link expires without being completed.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.expired",
"data": {
"id": "PAYR_oIPbFOXogbjW",
"additional_info": {
"email": "ajibola@busha.co",
"name": "Jibola Obi",
"phone_number": "",
"source": ""
},
"created_at": "2025-12-10T10:35:59.220244Z",
"expires_at": "2025-12-10T11:35:59.175239Z",
"fees": [],
"merchant_info": {
"email": "ajibola@busha.co",
"name": "Liverppol"
},
"pay_in": {
"address": "tb1qnltjz527u6pxvcavqwrrja6znyrgd9c2pcl7qu",
"expires_at": "2025-12-10T11:35:59.175239Z",
"network": "BTC",
"type": "address"
},
"rate": {
"product": "BTCNGN",
"rate": "136593125.15",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"reference": "PAYR_oIPbFOXogbjW",
"source_amount": "0.00036606",
"status": "expired",
"target_amount": "50001.27",
"timeline": {
"total_steps": 1,
"current_step": 1,
"transfer_status": "cancelled",
"events": [
{
"step": 1,
"done": true,
"status": "pending",
"title": "Transfer Started",
"description": "Waiting for your BTC deposit",
"timestamp": "2025-12-10T11:36:00.281594Z"
}
]
},
"updated_at": "2025-12-10T12:30:51.466553Z",
"source_currency": "BTC",
"target_currency": "NGN"
}
}
```
***
### payment\_request.failed
**Sent when:** Payment request fails due to an error.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.failed",
"data": {
"id": "PAYR_failed456",
"additional_info": {
"email": "customer@example.com",
"name": "Jane Smith",
"phone_number": "+2348098765432",
"source": "checkout"
},
"created_at": "2025-12-09T08:00:00.000000Z",
"fees": [],
"merchant_info": {
"email": "merchant@busha.co",
"name": "Liverpool"
},
"reference": "PAYR_failed456",
"source": "payment_link",
"source_amount": "16.91200347",
"source_id": "ORDER_789",
"status": "failed",
"target_amount": "25000",
"source_currency": "USDT",
"target_currency": "NGN",
"error": {
"code": "insufficient_funds",
"message": "Customer sent insufficient funds to complete payment"
},
"updated_at": "2025-12-09T08:30:00.123456Z"
}
}
```
***
### payment\_request.cancelled
**Sent when:** Payment request is manually cancelled by merchant or customer before completion.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "payment_request.cancelled",
"data": {
"id": "PAYR_Cancelled456",
"additional_info": {
"email": "customer@example.com",
"name": "Michael Johnson",
"phone_number": "+2347012345678",
"source": "email_invoice"
},
"created_at": "2025-12-09T07:30:00.000000Z",
"cancelled_at": "2025-12-09T08:15:00.123456Z",
"cancellation_reason": "Customer requested cancellation",
"fees": [],
"merchant_info": {
"email": "merchant@busha.co",
"name": "Liverpool"
},
"reference": "PAYR_Cancelled456",
"source": "payment_link",
"source_amount": "0.00033",
"source_id": "INV_2025_001",
"status": "cancelled",
"target_amount": "50000",
"source_currency": "BTC",
"target_currency": "NGN",
"rate": {
"product": "BTCNGN",
"rate": "151515151.52",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"timeline": {
"total_steps": 0,
"current_step": 0,
"transfer_status": "",
"events": []
},
"updated_at": "2025-12-09T08:15:00.123456Z"
}
}
```
***
## Ramp Events
Ramp events track on/off-ramp transactions where users convert between fiat and cryptocurrency through Busha's ramp service.
### ramp.transfer.pending
**Sent when:** A ramp transfer (fiat to crypto or crypto to fiat) has been initiated and is awaiting processing.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "ramp.transfer.pending",
"data": {
"id": "RAMP_TRF_abc123",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"ramp_type": "on_ramp",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"target_amount": "33.78",
"status": "pending",
"rate": {
"product": "NGNUSDT",
"rate": "1480.00",
"side": "buy",
"type": "FIXED"
},
"created_at": "2025-12-09T12:00:00.000000Z"
}
}
```
***
### ramp.transfer.completed
**Sent when:** Ramp transfer has been successfully completed and funds have been delivered.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "ramp.transfer.completed",
"data": {
"id": "RAMP_TRF_abc123",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"ramp_type": "on_ramp",
"source_currency": "NGN",
"target_currency": "USDT",
"source_amount": "50000",
"target_amount": "33.78",
"status": "completed",
"rate": {
"product": "NGNUSDT",
"rate": "1480.00",
"side": "buy",
"type": "FIXED"
},
"created_at": "2025-12-09T12:00:00.000000Z",
"completed_at": "2025-12-09T12:05:30.123456Z"
}
}
```
***
### ramp.transfer.failed
**Sent when:** Ramp transfer fails due to an error.
```json theme={null}
{
"business_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"event": "ramp.transfer.failed",
"data": {
"id": "RAMP_TRF_failed789",
"profile_id": "BUS_CQr0jPzGGzmn1uW5W7OVs",
"ramp_type": "off_ramp",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.001",
"target_amount": "135796.71",
"status": "failed",
"error": {
"code": "bank_account_invalid",
"message": "Recipient bank account details are invalid"
},
"created_at": "2025-12-09T12:00:00.000000Z",
"failed_at": "2025-12-09T12:03:00.123456Z"
}
}
```
***
## Setting Up Webhooks
To configure webhooks in your Busha account and implement webhook handlers, see our [Webhooks Setup Guide](/guides/webhooks/setup) for detailed instructions.
## See Also
* [Verify Customer Identity](/guides/customers/verify-identity) - Learn about customer verification flow
* [Create Individual Customer](/guides/customers/create-individual) - Set up individual customers
* [Create Business Customer](/guides/customers/create-business) - Set up business customers
***
# Compliance
Source: https://docs.busha.io/overview/compliance
Understand Busha's compliance requirements. KYC, AML policies, and regulatory guidelines for your integration.
Busha, like other financial institutions, operates under strict regulatory requirements designed to combat financial crime and ensure a secure financial ecosystem. These requirements mandate that we verify the identity of all our customers, whether they are individuals or businesses.
In a hurry? See the summarized requirements for each business types [in this
table](#required-documents-by-business-entity-type).
## Regulatory Pillars
* **Anti-Money Laundering (AML) Regulations:** These laws are designed to prevent the use of financial systems for illicit activities like money laundering, which involves disguising illegally obtained funds as legitimate income.
* **Know Your Customer (KYC) Requirements:** KYC is a critical part of AML, requiring us to identify and verify the identity of our customers. This helps us understand who we are doing business with and assess potential risks.
* **Counter-Terrorism Financing (CTF) Laws:** These laws aim to disrupt the flow of funds to terrorist organizations.
* **Local Financial Regulations:** In addition to international standards, Busha adheres to specific financial regulations in Nigeria and Kenya, where we operate.
## Impact on Your Transactions
These regulations directly influence how you interact with Busha. To ensure compliance and the security of our platform:
* **Mandatory Verification:** All customers must undergo and pass the verification process before they can conduct any transactions.
* **Document Submission:** Providing the required identification and business documents is not optional; it's a mandatory step in activating your account.
* **Transaction Limits:** Your verification status determines the transaction limits applied to your account. Fully verified accounts typically have higher limits.
* **Account Activation:** If verification fails or documents are not submitted, your account cannot be fully activated for transactions.
## KYC Requirements for Individual Customers
To verify individual customers, Busha collects specific identity documents and performs a proof-of-identity step. The exact requirements vary slightly by country to align with local regulations and common identification methods.
### Nigeria
* **Primary ID:** You can provide one of the following: a National Identification Number (NIN) or a national passport.
* **Proof of Identity:** A selfie is required to confirm that the person providing the documents is indeed the account holder.
### Kenya
* **Primary ID:** A National ID card is required.
* **Proof of Identity:** Similar to Nigeria, a selfie is needed for proof of identity.
### The Verification Process
The individual customer verification process follows a clear sequence:
1. **Document Provision:** You submit the required primary ID and selfie through the Busha platform.
2. **Document Review:** Our compliance team reviews the submitted documents for authenticity, validity, and adherence to technical requirements.
3. **Identity Verification:** Once the documents are verified, your identity is confirmed.
4. **Account Activation:** Upon successful identity verification, your account is fully activated, allowing you to conduct transactions within your designated limits.
### Technical Requirements for Document Submission
When submitting your documents, please ensure they meet the following technical specifications to facilitate a smooth verification process:
#### Via Dashboard
* **Format:** Accepted file formats include PDF, JPG, JPEG, and PNG
* **File Size:** Each file should not exceed 4MB
* **Clarity:** Photos of your primary ID must be clear, well-lit, and easily readable with no glare or obstructions your selfie should clearly show your facial features, allowing for easy identification
#### Via the API
* **Format:** All files (images) must be submitted in Base64 format
* **File Size:** Each file should not exceed 4MB
* **Clarity:** Same clarity requirements as dashboard submissions apply
## Requirements for Business Customers (KYB - Know Your Business)
For businesses, the verification process, often referred to as Know Your Business (KYB), is more comprehensive due to the complexity of business structures and ownership. This ensures that Busha understands the nature of the business, its ownership, and its operational legitimacy.
Busha offers tiered verification levels, each with specific document requirements and transaction limits.
### Tier 1 Verification (Basic Business Verification)
Tier 1 verification allows you to access basic business features with standard transaction limits.
#### Required Documents
* **Certificate of Incorporation**: Legal proof that the business is officially registered.
* **Corporate Registry Extract**: A document from the relevant corporate registry detailing key information about the business (e.g., directors, registered address).
#### Transaction Limits
| Business Type | Account Type | Daily Limit | Monthly Limit |
| :--------------------------------- | :----------- | ----------: | ------------: |
| Business Names/Sole Proprietorship | Main | \$100,000 | \$3,000,000 |
| Business Names/Sole Proprietorship | Sub-Account | \$100,000 | \$3,000,000 |
| Limited Liability Company | Main | \$1,000,000 | \$20,000,000 |
| Limited Liability Company | Sub-Account | \$1,000,000 | \$20,000,000 |
There is no Tier 2 verification for Business Names/Sole Proprietorships.
### Tier 2 Verification (Unlimited Transaction Limits)
Tier 2 verification removes all transaction limits and unlocks full platform capabilities. This applies to **Limited Liability Companies only**.
#### Required Documents (in addition to Tier 1 documents)
* **Memorandum of Association Articles (Memart)**: A legal document outlining the company’s objectives and how it will achieve them.
* **Corporate Structure Chart**: A visual representation of the ownership and management hierarchy of the business.
* **Board Resolution**: Official minutes or a statement from the company’s board of directors authorizing specific actions or individuals.
* **Anti-Money Laundering Policy**: The business’s internal policy for preventing money laundering and other financial crimes.
* **Regulatory Licenses**: Any specific licenses required for the business to operate in its industry (e.g., financial services license, trading license).
* **Proof of Wealth**: Documentation demonstrating the source of the business’s funds.
* **Proof of Address**: Documents confirming the official registered address of the business.
#### Transaction Limits
| Business Type | Account Type | Daily Limit | Monthly Limit |
| :------------------------ | :----------- | :---------- | :------------ |
| Limited Liability Company | Main | Unlimited | Unlimited |
| Limited Liability Company | Sub-Account | Unlimited | Unlimited |
### The Verification Process
The business verification process mirrors the individual process but with a focus on comprehensive business information:
1. **Document Provision:** The business provides all the required corporate and legal documents for the desired verification tier.
2. **Document Review:** Our compliance team meticulously reviews each document for authenticity, completeness, and adherence to legal standards.
3. **Identity Verification:** Once the business's identity and its key stakeholders are verified, the KYB process is completed.
4. **Account Activation:** Upon successful verification, the business account is activated at the appropriate tier level, enabling it to conduct transactions on the Busha platform.
#### Via The Dashboard
* **Format:** Accepted file formats include PDF, JPG, JPEG, and PNG
* **File Size:** The maximum file size per document is 4MB
* **Validity:** All submitted documents must be official, current, and not expired
#### Via The API
* **Format:** All files must be in Base64 format
* **File Size:** The maximum file size per document is 4MB
* **Validity:** All submitted documents must be official, current, and not expired
## Understanding Business Entity Types
The specific onboarding requirements for businesses can vary significantly based on their legal structure. Understanding these different entity types is crucial for preparing the correct documentation.
### Sole Proprietorships
**Definition:** Businesses owned and run by a single individual.
**Liability:** The owner has unlimited personal liability for business debts.
**Simplicity:** This is typically the simplest business structure to set up.
**Required Documents:** Business License, Trade Name Registration (DBA - "Doing Business As"), Tax registration documents.
### General Partnerships (GP)
* **Definition:** Two or more individuals share ownership and management responsibilities.
* **Liability:** All partners have unlimited personal liability.
* **Required Documents:** Partnership Agreement, Business License listing all partners, Trade Name Registration (DBA) listing all partners.
### Limited Partnerships (LP)
* **Definition:** Include both general partners (with unlimited liability and management control) and limited partners (with limited liability and no management control).
* **Required Documents:** Certificate of Limited Partnership (filed with government), Limited Partnership Agreement, Registration documents.
### Limited Liability Partnerships (LLP)
* **Definition:** Partners have limited personal liability, typically protecting them from the actions of other partners. Common in professional services.
* **Required Documents:** Certificate of Limited Liability Partnership, LLP Agreement, Registration documents.
### Corporations
**Definition:** A separate legal entity from its owners (shareholders).
**Liability:** Shareholders have limited liability, meaning their personal assets are generally protected from business debts.
**Required Documents:** Articles of Incorporation (filed with government), Certificate of Incorporation, Corporate Bylaws, Shareholder Agreements.
### Limited Liability Companies (LLC)
**Definition:** A hybrid structure combining the limited liability of a corporation with the pass-through taxation and flexibility of a partnership.
**Liability:** Members have limited liability.
**Management:** Offers a flexible management structure.
**Required Documents:** Articles of Organization (filed with government), Operating Agreement, Membership Certificates, Registration documents.
### Nonprofit Organizations
**Definition:** Established for charitable, educational, religious, or social purposes, rather than for profit.
**Tax Status:** Can apply for tax-exempt status.
**Ownership:** No individual beneficial shareholders.
**Required Documents:** Articles of Incorporation, Certificate of Incorporation, Tax-exempt status application (if applicable), Bylaws.
### Foundations
**Definition:** Entities established to hold and manage assets for charitable or philanthropic purposes.
**Governance:** Governed by a board of trustees or directors.
**Ownership:** No individual beneficial shareholders.
**Required Documents:** Articles of Incorporation, Certificate of Incorporation, Foundation Charter or Trust Deed, Board Resolutions.
### Trusts
**Definition:** A legal arrangement where a trustee holds assets for the benefit of beneficiaries.
**Management:** Managed according to the specific terms outlined in a trust agreement.
**Variety:** Various types exist for different purposes (e.g., living trusts, testamentary trusts).
**Required Documents:** Trust Deed (or Trust Agreement), Certificate of Trust, Notarized Trustee's Affidavit, Trust registration documents.
## Required Documents by Business Entity Type
Business Entity Type
Required Documents
Sole Proprietorships
Business License
Trade Name Registration (DBA - "Doing Business As")
Tax registration documents
General Partnerships (GP)
Partnership Agreement
Business License listing all partners
Trade Name Registration (DBA) listing all partners
Limited Partnerships (LP)
Certificate of Limited Partnership (filed with government)
Limited Partnership Agreement
Registration documents
Limited Liability Partnerships (LLP)
Certificate of Limited Liability Partnership
LLP Agreement
Registration documents
Corporations
Articles of Incorporation (filed with government)
Certificate of Incorporation
Corporate Bylaws
Shareholder Agreements
Limited Liability Companies (LLC)
Articles of Organization (filed with government)
Operating Agreement
Membership Certificates
Registration documents
Nonprofit Organizations
Articles of Incorporation
Certificate of Incorporation
Tax-exempt status application (if applicable)
Bylaws
Foundations
Articles of Incorporation
Certificate of Incorporation
Foundation Charter or Trust Deed
Board Resolutions
Trusts
Trust Deed (or Trust Agreement)
Certificate of Trust
Notarized Trustee's Affidavit
Trust registration documents
# Customers
Source: https://docs.busha.io/overview/customers
Learn how to create and manage customer profiles in Busha. Handle KYC, balances, and customer transactions.
Busha Business accounts extend beyond just managing your enterprise's financial flows. They offer a robust framework for programmatically overseeing and executing transactions on behalf of your end-customers — be they individual users or other businesses. This capability allows you to integrate a multi-layered financial service directly within your application, abstracting underlying complexities.
At its core, Customer Management introduces the concept of operating within a **customer context**. This means that while your Busha Business account remains the primary authenticated entity, you can designate specific transactions to occur on a particular end-customer's behalf, affecting their dedicated balances within your Busha ecosystem.
## Core Concept
Within Busha's Customer Management framework, an **end-customer** is an entity you define and manage under your Busha Business account. This distinct customer profile allows for:
* **Dedicated Balances:** Each end-customer can hold their separate fiat and crypto balances, ensuring clear segregation of funds.
* **Transaction Attribution:** All operations performed within a customer's context are accurately attributed to them, simplifying reconciliation and reporting for your business.
* **Contextual Operations:** Busha business owners can perform any transaction available to a standard Busha account (e.g., deposits and payouts) while specifying that the action is for, and impacts, a particular end-customer's balances. This is managed through explicit identification of the customer in API requests or via specific UI flows in the dashboard.
## Architectural Overview: Extending Your API Control
The Customer Management feature extends the existing Busha Business API, allowing you to programmatically control the lifecycle of your customers and their associated financial activities. This is achieved through dedicated customer management API endpoints and a mechanism to apply a customer context to general transaction endpoints.
### API-driven customer lifecycle
For API requests involving a customer, the `X-BU-PROFILE-ID` field is included
in the request header. The value for this field is the customer ID for whom
the request is performed on their behalf.
**Example:**
```bash theme={null}
curl -X POST https://api.busha.co/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_API_KEY" \
-H "X-BU-PROFILE-ID: CUS_abc123xyz789" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.001"
}'
```
In this example, the transfer will be executed on behalf of the customer with ID `CUS_abc123xyz789`, affecting their balance rather than your main business account balance.
Your integration can manage customers through the following key API interactions:
#### Creating customer profiles
You can provision new individual or business customer profiles under your Busha Business account via a dedicated API endpoint (e.g., `POST /v1/customers`). This allows for automated onboarding processes directly from your application. Each successfully created customer will be assigned a unique `customer_id`.
#### Retrieving and listing customers
To manage your customer base, you can retrieve a list of all your registered customers (e.g., `GET /v1/customers`). This provides an overview of their profiles, enabling you to retrieve specific customer details as needed.
#### Executing transactions within a customer context
This is where the power of Customer Management is most evident. When performing a transaction via API (e.g., initiating a payout), you use your **Secret API Key** for authentication (proving your business's identity).
* To specify that the transaction is on behalf of one of your customers, you will include their unique `customer_id` in a designated **HTTP header** (e.g., `X-BU-PROFILE-ID: your_customer_id`).
* The Busha API will then process the request, impacting the balances and transaction history associated with that specific `customer_id`. The same underlying logic applies when performing actions via the Busha Dashboard.
## Benefits for Technical Integrators
* **Unified API Interaction:** Leverage a single set of Busha API credentials (`Secret API Key`, `X-BU-PROFILE-ID`) to manage both your own business's funds and those of your end-customers by simply varying the `customer_id` context.
* **Simplified Fund Segregation:** Busha handles the underlying complexity of maintaining separate balance accounts for each of your customers, reducing your development burden for ledger management.
* **Granular Transaction Attribution:** Every operation is precisely attributed to the correct end-customer, simplifying reconciliation, reporting, and audit trails for your platform.
* **Customizable User Journeys:** Design your application's frontend entirely to your specifications, while relying on Busha's robust backend for secure and compliant financial operations for your customers.
* **Automated Compliance:** One of the most significant advantages of managing your customers through Busha Business is the ability to offload the complexities of regulatory compliance. By integrating your customers into Busha, you can now rely on Busha's established and trusted infrastructure to handle critical compliance functions seamlessly:
* **KYC (Know Your Customer):** We manage the verification processes for individual customers, ensuring their identity is confirmed in line with regulatory requirements.
* **KYB (Know Your Business):** For your business customers, Busha handles the necessary due diligence to verify their legal entity status and operational legitimacy.
* **KYT (Know Your Transaction):** Our systems continuously monitor and analyze transactions for suspicious activities, helping to detect and prevent financial crime.
* **Travel Rule Compliance:** For crypto transfers that fall under the Travel Rule, Busha's infrastructure assists in collecting and transmitting required originator and beneficiary information, ensuring adherence to global anti-money laundering (AML) standards.
This comprehensive compliance coverage means you can focus on your core business offerings, confident that the intricate and ever-evolving regulatory landscape is being managed by a specialized and reliable partner.
## What's Next?
To begin integrating Customer Management into your application:
* [How to Create and Manage Customers via API](/guides/customers/create-individual): A practical guide to programmatically setting up customer profiles.
* [How to Initiate Transactions on Behalf of a Customer](/guides/customers/transactions-on-behalf): Learn the practical steps for executing financial operations in a customer's context.
* [Busha API Reference: Customer Endpoints](/api-reference/customers/list-customers): Explore the detailed specifications for creating, retrieving, and managing customer profiles.
# Fees
Source: https://docs.busha.io/overview/fees
Understand Busha's fee structure.
## Fiat
**Nigeria**
Transaction Type
Associated Fee
Deposit
NGN 150
Withdrawal
NGN 107.50 (7.5% VAT inclusive)
**Kenya**
Transaction Type
Associated Fee
Deposit
1% margin on deposit volume
Withdrawal
KES 330
## Crypto
Asset
Network
Withdrawal Fee
Bitcoin (BTC)
BTC
0.00005 BTC
Binance Coin (BNB)
BNB-BEP20 (BSC)
0.001 BNB
BNB (BSC)
0.001 BNB
Cardano (ADA)
ADA
1.6 ADA
Dogecoin (DOGE)
DOGE
3 DOGE
Ethereum (ETH)
ETH-BASE (BASE)
0.0005 ETH
ETH
0.0005 ETH
Litecoin (LTC)
LTC
0.000025 LTC
Polygon (MATIC)
BNB (BSC)
0.15 MATIC
Ripple (XRP)
XRP
0.25 XRP
Shiba Inu (SHIB)
SHIB-ERC20 (ETH)
700,000 SHIB
SHIB (BSC)
15,000 SHIB
Solana (SOL)
SOL
0.015 SOL
Stellar (XLM)
XLM
1 XLM
Tether (USDT)
USDT-BEP20 (BSC)
1 USDT
USDT-ERC20 (ETH)
3 USDT
USDT-TRC20 (TRX)
3 USDT
USDT-XPL (Plasma)
1 USDT
USDT (SOL)
1 USDT
TRON (TRX)
TRX
3 TRX
USD Coin (USDC)
USDC-BASE (BASE)
0.1 USDC
USDC-ERC20 (ETH)
3 USDC
USDC (POL)
0.5 USDC
USDC (XLM)
1 USDC
USDC (SOL)
0.5 USDC
# Headers
Source: https://docs.busha.io/overview/headers
Learn the custom headers Busha uses, what they do, and when to include them.
Busha API requests use a small set of custom headers in addition to standard HTTP headers such as `Content-Type`. This page explains the headers you will most commonly encounter and when to use them.
## Authorization
The `Authorization` header is required for most authenticated requests. It carries your business Secret API Key as a Bearer token.
```http theme={null}
Authorization: Bearer YOUR_SECRET_KEY
```
Use it for quotes, transfers, customers, recipients, balances, and most other business-owned resources. See [Make your first request](/guides/getting-started/make-first-request).
Pledge endpoints are the exception. They require a customer-scoped OAuth2 access token in this header instead of your business Secret Key. See [Pledges: Before you begin](/guides/pledges/introduction#before-you-begin).
## X-BU-PROFILE-ID
Include `X-BU-PROFILE-ID` when a request should act on behalf of a specific customer rather than your business account.
```http theme={null}
X-BU-PROFILE-ID: CUS_abc123xyz789
```
This header is optional on most endpoints. Omit it and the request uses your business account by default. See [Customers](/overview/customers).
## X-BU-PUBLIC-KEY
Use `X-BU-PUBLIC-KEY` instead of `Authorization` for client-facing or lightly authenticated endpoints, especially payment requests.
```http theme={null}
X-BU-PUBLIC-KEY: pub_uibaidu930ani
```
Your public key is safe to expose in frontend code. Use it when creating or retrieving payment requests and when working with the Commerce SDK. See [Retrieve a payment request](/guides/payment-requests/retrieve-payment).
Never use your Secret Key where a Public Key is expected, and never expose your Secret Key in client-side code.
## X-BU-Version
`X-BU-Version` lets you select a specific request and response schema version for endpoints that have changed over time.
```http theme={null}
X-BU-Version: 2025-07-11
```
This header is optional. If you omit it, Busha uses the default version for the endpoint. It is currently used on recipients endpoints and other endpoints that support versioned schemas. The older `X-BU-VERSION` header is deprecated and should not be used.
## X-Request-Id
`X-Request-Id` is a response header. Every API response includes a unique identifier for that call.
```http theme={null}
X-Request-Id: req_JfPBXEC5rLHc
```
Use it when you contact Busha support or need to debug a specific request. Request IDs are retained for 21 days. See [Request IDs](/guides/request-id/request-id).
## x-bu-signature
`x-bu-signature` is a webhook-specific header that Busha sends to your webhook endpoint. You do not send it to Busha.
```http theme={null}
x-bu-signature:
```
Use it to verify that an incoming webhook came from Busha. Compute an HMAC-SHA256 signature of the raw request body using your webhook secret, then compare it with this header value. See [Set up webhooks](/guides/webhooks/setup#verifying-webhook-signature).
## Quick reference
| Header | Direction | Required | Purpose |
| ----------------- | ------------------ | --------------------------- | ----------------------------------------- |
| `Authorization` | Request | Yes (most endpoints) | Secret Key or OAuth2 access token |
| `X-BU-PROFILE-ID` | Request | No | Scope a request to a specific customer |
| `X-BU-PUBLIC-KEY` | Request | Yes (Payment Requests only) | Public Key for client-facing endpoints |
| `X-BU-Version` | Request | No | Select a specific endpoint schema version |
| `X-Request-Id` | Response | Always present | Unique ID for support and debugging |
| `x-bu-signature` | Response (webhook) | Always present | Verify webhook authenticity |
# Multi-Currency Accounts
Source: https://docs.busha.io/overview/multi-currency-accounts
Manage multiple currencies in a single account. Support NGN, KES, USDT, BTC, and more in your application.
Busha's Multi-Currency Accounts (MCAs) empower businesses to seamlessly manage funds across various global currencies. This functionality is designed to streamline your financial operations, simplify cross-border transactions, and provide your customers with a smooth cross-border payment experience.
At its core, a Multi-Currency Account allows your business to hold, receive, and send funds in different currencies from a single, unified platform, eliminating the complexities often associated with cross-border banking.
## Why Multi-Currency Accounts Matter
In today's global economy, businesses often deal with customers, suppliers, and partners operating in diverse currencies. Multi-Currency Accounts are crucial because they:
* **Reduce Conversion Costs:** Minimize fees and potential losses from frequent currency conversions by holding funds in their native currency.
* **Improve Cash Flow Management:** Gain a consolidated view of your finances across all currencies, enabling better financial planning and liquidity management.
* **Enhance Customer Experience:** Offer your customers the convenience of paying in their preferred currency, simplifying transactions and fostering trust.
* **Streamline Operations:** Consolidate international financial operations into a single, easy-to-manage system.
## Key Features of Busha Multi-Currency Accounts
Busha's MCA solution comes with robust features designed for global financial flexibility:
### Flexible Account Creation
Busha enables you to easily and instantly create dedicated accounts for multiple currencies, supporting your global transactions effortlessly. This allows you to manage various currencies (e.g., USD, EUR, GHS, NGN, BTC, ETH) all under one unified Busha platform, streamlining your international financial operations.
### Real-Time Balances
Busha provides instantaneous visibility into your account balances across all supported currencies, allowing you to stay informed and in control of your finances. You can track individual currency accounts or view consolidated totals in real-time, ensuring you always have an up-to-date view of your financial position.
### Seamless Currency Conversion
Busha empowers you to effortlessly convert funds between supported currencies within your accounts at competitive rates. This capability helps you optimize capital management, reduce friction, and manage international payments efficiently, giving you the flexibility to move funds where they're needed most.
### Comprehensive Reporting
Busha provides access to detailed transaction histories and account activity through robust reporting tools, ensuring full transparency across all your currency accounts. This comprehensive reporting simplifies reconciliation, auditing, and financial planning for your business, giving you the insights needed to make informed decisions.
## What's Next?
Now that you understand the benefits and features of Busha's Multi-Currency Accounts, you can learn how to manage them:
* [How-to Guide: Manage Your Account Balances](/guides/balance/manage-balance-accounts): Learn how to retrieve and interact with your multi-currency balances via the API.
* [Reference: Supported Currency Pairs](/api-reference/pairs/list-trading-pairs): Get a comprehensive list of all currency pairs supported for conversions.
* [API Reference: Multi-Currency Accounts Endpoints](/api-reference/currencies/retrieve-supported-currencies): Dive into the technical specifications for all MCA-related API calls.
# Quotes
Source: https://docs.busha.io/overview/quotes
Learn how quotes work in Busha. Lock in exchange rates and fees before executing transactions.
At Busha, a **Quote** is the fundamental building block for nearly every financial operation that involves an asset transfer, such as currency conversions, deposits, or payouts. It precisely describes a proposed asset transfer between a **source** and a **destination**, ensuring transparency and accuracy before any funds move.
Think of a Quote as a dynamic, real-time snapshot of a proposed transaction. It locks in the terms, such as exchange rates and specific amounts, for a brief period, giving you certainty and control over the outcome of your financial operations.
## What is a Quote? The Core Concept
A Quote is a preliminary agreement that describes an asset transfer. Assets can move between:
* **Busha Balances:** Your internal multi-currency accounts on the Busha platform.
* **External Accounts:** Such as crypto wallet addresses, external bank accounts, or mobile money wallets.
Every Quote, at its most basic level, specifies four crucial values that define the proposed transfer:
* `source_currency`: The currency you're sending (e.g., BTC, NGN).
* `target_currency`: The currency you're receiving (e.g., NGN, USD).
* `source_amount`: The amount of `source_currency` to be sent.
* `target_amount`: The amount of `target_currency` to be received.
* `quote_currency`: The fiat currency (e.g., NGN, KES) that the user wants to use as a reference point for the value of their transaction. It's the currency in which the user *thinks* about the desired value of their crypto.
* `quote_amount`: The specific amount of the `quote_currency` that the user wishes to transact.
## Key Properties of a Busha Quote Explained
When you request a Quote from the Busha API, the response contains several key properties that detail the proposed transaction. Understanding these components is essential for working with Busha's transaction flow:
### Source, destination, and their amounts
A Quote always involves a `source_currency` (the asset being sent) and a `target_currency` (the asset being received).
**Crucially, when you request a Quote, you specify either the `source_amount` or the `target_amount`, but never both.**
* If you specify `source_amount` (e.g., "I want to send 0.001 BTC"), Busha calculates the `target_amount` (how much NGN you'll receive) based on the current exchange rate.
* If you specify `target_amount` (e.g., "I want to receive 10,000 NGN"), Busha calculates the `source_amount` (how much BTC you need to send) based on the current exchange rate.
The Quote response will then provide both the calculated `source_amount` and `target_amount` values for the proposed transfer.
### Quote currency and quote amount
When you provide `quote_currency` and `quote_amount`, Busha takes on the responsibility of calculating either the `source_amount` (how much crypto you need to send) or the `target_amount` (how much crypto you will receive). This calculation is performed dynamically based on the current, real-time exchange rates between the specified `source_currency`, `target_currency`, and the `quote_currency`.
### Key benefits and purpose
1. **Simplified User Experience:** Users no longer need to manually calculate how much crypto they need to buy or sell to achieve a specific fiat value. They simply state the fiat value they're aiming for.
2. **Fiat-Centric Transactions:** This feature caters to users who think about their crypto transactions in terms of their local fiat currency. For example, instead of saying "I want to buy 0.005 BTC," they can say "I want to buy ₦50,000 worth of BTC."
3. **Automatic Amount Calculation:** The system handles the complex and often fluctuating nature of exchange rates, ensuring the user gets the correct amount of crypto for their desired fiat value, or vice versa.
4. **Inclusion of Fees (for external transfers):** When `pay_out` is an external address, the system will factor in network fees into its calculation, ensuring that the `quote_amount` is accurately reflected in the final crypto amount.
**Restrictions and Requirements:**
* `quote_currency` **must be fiat:** This parameter is strictly for national currencies (e.g., NGN, KES).
* `source_currency` **must be crypto when using** `quote_currency`/`quote_amount`: This implies that this feature is primarily for scenarios where users are converting fiat value into crypto, or using crypto to achieve a specific fiat value.
* `target_currency` **can be crypto or fiat:** This provides flexibility, allowing users to either receive crypto or convert their crypto to fiat, all while specifying their desired value in a fiat `quote_currency`.
### Transfer channels (`pay_in` and `pay_out`)
While the core of a Quote defines *what* is being transferred (currencies and amounts), the optional `pay_in` and `pay_out` objects specify *how* the transfer will be facilitated.
* `pay_in`: Provides details about where the source currency will be sent in from.
* `pay_out`: Provides details about the destination of the target currency.
Including these details in the Quote request allows Busha to accurately estimate costs and provide the correct instructions for the specific transfer method.
If either of the `pay_in` and `pay_out` objects are not included in the quote
object; Busha assumes that the operation is to be executed from the balance.
The transfer channels currently supported are:
* Cryptocurrency address
* Bank transfers **(Nigeria)**
* Mobile money **(Kenya)**
### The `pay_in` object
The fields in the `pay_in` object differ from transfer channel to transfer channel.
**Account balance**
```json theme={null}
"pay_in": {
"type": "balance"
}
```
The mobile number associated with the mobile money account for deposit.
"+254 702288461"
### The `pay_out` object
The fields in the `pay_out` object differ from transfer channel to transfer channel.
For mobile transfer and mobile money payouts, the recipient should be
registered within your Busha business account.
**Cryptocurrency**
```json theme={null}
{
"type": "address",
"address": "tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq",
"network": "BTC",
"memo": ""
}
```
Key
Description
Value
type
Specifies the payout type.
"address"
address
The cryptocurrency address for the payout.
"tb1qzw4ynldc55lpkx3vcsk03susv9nwzj6qp78qsq"
network
The blockchain network (e.g., Bitcoin, Ethereum) for the payout.
"BTC"
memo
An optional field for networks that require a memo/tag/destination tag.
The ID of the pre-registered mobile money recipient for the payout.
"677bbf9c7cf061f23784555a"
### Rate object
The `rate` object nested within the Quote response describes the precise exchange value used for the conversion between the `source_currency` and `target_currency` at that moment.
It typically includes the `pair` (e.g., `BTCNGN`), the `rate` itself, the `side` of the transaction (e.g., `buy` or `sell` from Busha's perspective), and the `type` of rate (e.g., `FIXED`). This `rate` is fundamental to how Busha validates and calculates the `source_amount` and `target_amount`.
### Fees object
The `fees` object within the Quote response represents any service charges or amounts that will be deducted from the `source_amount` (or sometimes the `target_amount`, depending on the transaction type) when the Quote is executed. This provides full transparency on transaction costs.
### Quote expiration (expires\_at)
**All Quotes expire!**
Every Quote object includes an `expires_at` timestamp. This specifies the exact time after which the Quote becomes invalid and can no longer be used to make any transfers.
Quotes typically have a short validity period (e.g., a few seconds to a few minutes) to account for volatility in market prices, especially for cryptocurrencies. If you attempt to execute a transaction with an expired Quote, the request will be executed at the current market price.
### Example of a Quote object
Here is a typical structure of a Quote object that you would receive from the Busha API. This example illustrates a proposed "sell" operation (where you're selling BTC to get NGN):
```json theme={null}
{
"status": "success",
"message": "Created quote successfully",
"data": {
"id": "QUO_uNiw1CDqGrdIlK15N0bu1",
"profile_id": "BUS_VI3eUQSbGBx4EQuQWYDU1",
"source_currency": "BTC",
"target_currency": "NGN",
"source_amount": "0.00007051",
"target_amount": "10050.58",
"rate": {
"product": "BTCNGN",
"rate": "142541279.55",
"side": "sell",
"type": "FIXED",
"source_currency": "BTC",
"target_currency": "NGN"
},
"fees": [],
"reference": "QUO_uNiw1CDqGrdIlK15N0bu1",
"status": "pending",
"expires_at": "2025-02-20T06:57:05.059512+01:00",
"created_at": "2025-02-20T06:27:05.059464+01:00",
"updated_at": "2025-02-20T06:27:05.059464+01:00"
}
}
```
This example represents a sell operation for BTC to your NGN Busha balance,
where you specified the desired `target_amount` in NGN, and the API calculated
the `source_amount` in BTC required.
## Why Quotes are the Backbone of Busha's Flow
The reason Quotes are fundamental to Busha's API is that **every transaction that involves an exchange or transfer of assets (e.g., currency conversion, deposit, payouts, buying/selling crypto) must begin with a Quote.**
By mandating a Quote first, Busha ensures:
* **Price Certainty:** You know the exact exchange rate, fees, and final amounts before committing to any transaction. This eliminates surprises.
* **Transparency:** All associated costs and conditions are clearly presented within the Quote object.
* **User Confirmation:** Your application can present the precise terms of a transaction to your end-user for their explicit confirmation before proceeding, enhancing trust and preventing errors.
* **Safety & Pre-validation:** A Quote acts as a real-time validation step, confirming that the proposed transaction is valid and executable under current market conditions and system availability, considering the specific transfer methods (`pay_in` and `pay_out`) if provided.
# Transactions
Source: https://docs.busha.io/overview/transactions
Track and monitor all transaction activity in Busha. View history, statuses, and transaction details.
A **Transaction** in Busha Business is a historical record of any financial activity that affects an account balance. While Transfers represent the process of moving assets, Transactions represent the ledger entries that record all balance changes, providing a complete, immutable history of financial activity.
## What is a Transaction?
A Transaction is a record of a completed financial event that has impacted a balance on the Busha platform. Transactions serve as the official ledger of all account activity, providing a historical record of all balance changes, an audit trail for compliance and reconciliation, user-facing statements for account activity, and reporting data for analytics and accounting.
### Transactions vs. transfers
It's important to understand the distinction between Transactions and Transfers:
Aspect
Transfer
Transaction
Purpose
Process of moving assets
Record of balance change
Lifecycle
Has multiple statuses (pending, processing, completed)
Always completed
Timing
Created when initiated, updated until complete
Created only when finalized
Use Case
Track asset movement in progress
View historical account activity
## Core Components of a Transaction
Every Transaction contains these essential pieces of information:
### Identification
* **`id`**: Unique identifier for the transaction
* **`reference`**: A tracking reference
* **`user_id`**: The user who owns this transaction
* **`profile_id`**: The profile (business or customer) the transaction belongs to
### Amount and value
* **`amount`**: How much was transacted
* **`currency`**: Which currency (BTC, NGN, USDT, etc.)
* **`rate`**: The exchange rate used
* **`is_fiat`**: Boolean indicating if the currency is fiat
* **`is_credit`**: Boolean indicating if this adds or removes from balance
### Balance information
The transaction response includes a complete snapshot of the account balance:
* **`total_balance`**: Total balance after the transaction
* **`available_balance`**: Balance available for immediate use
* **`pending_balance`**: Funds pending confirmation
* **`hold`**: Funds temporarily held (e.g., for open orders)
* **`savings`**: Funds in savings/locked accounts
This balance snapshot helps you reconcile accounts and verify that transactions were processed correctly.
### Transaction metadata
The `meta` object contains transaction-specific details:
#### Balance snapshot
Shows balance state after the transaction:
```json theme={null}
{
"balance": {
"total": "610000",
"available": "610000"
}
}
```
#### Amount breakdown
Detailed breakdown of amounts:
```json theme={null}
{
"amounts": {
"fee": "100",
"amount_paid": "200100",
"amount_added": "200000"
}
}
```
#### Fee details
Fee information:
```json theme={null}
{
"fee": {
"amount": "100",
"currency": "NGN"
}
}
```
#### Price information
Transaction pricing:
```json theme={null}
{
"price": {
"amount": "1",
"currency": "NGN"
}
}
```
### Source/destination details
For deposits and withdrawals:
```json theme={null}
{
"source": {
"type": "bank_transfer",
"account_name": "John Doe",
"account_number": "0320484721"
}
}
```
### Crypto transaction details
For blockchain transactions:
* **`address`**: Blockchain address
* **`blockchain_url`**: Link to view transaction on blockchain explorer
* **`confirmations`**: Number of blockchain confirmations received
* **`required_confirmations`**: Number of confirmations needed
### Conversion details
For buy, sell, and convert transactions:
* **`credit`**: What was added to the balance
* **`debit`**: What was removed from the balance (e.g., "USDT 10")
* **`rate`**: The conversion rate used (e.g., "NGN 1474.86")
* **`fiat_value`**: Fiat equivalent value
* **`fiat_currency`**: The fiat currency for valuation
## Transaction Types
Transactions are categorized by type to make filtering and reporting easier:
| Transaction Type | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------- |
| **Deposits** | Incoming deposits to Busha balances from external sources. |
| **Buys** | Cryptocurrency purchase transactions where fiat currency was used to acquire crypto. |
| **Sells** | Cryptocurrency sale transactions where crypto was converted to fiat currency. |
| **Converts** | Currency conversion transactions within Busha balances (crypto-to-crypto or crypto-to-fiat). |
| **Withdrawals** | Outgoing withdrawals from Busha balances to external accounts. |
| **Fees** | Fee transactions for various operations like deposits, withdrawals, conversions, and other services. |
# Transfers
Source: https://docs.busha.io/overview/transfers
Understand how to create and manage transfers in Busha. Execute quotes and move funds between accounts.
A **Transfer** in Busha Business is the execution of a previously created Quote. While a Quote describes the proposed terms of an asset transfer, a Transfer is the actual process of moving those assets between sources and destinations according to those terms.
Transfers are the core mechanism through which all asset movements happen on the Busha platform. This includes depositing funds, converting between currencies, or sending payouts to external accounts.
## The Relationship Between Quotes and Transfers
Understanding the relationship between Quotes and Transfers is fundamental to using Busha Business:
* **Quote**: Describes the proposed transaction (exchange rates, amounts, fees)
* **Transfer**: Executes the transaction and tracks its progress
### The workflow is always
1. Create a Quote to lock in rates and terms
2. Present the Quote details to your user for confirmation
3. Create a Transfer using the Quote ID to execute the transaction
4. Monitor the Transfer status to track completion
**A Quote must be created before a Transfer can be initiated.** The Quote
locks in the exchange rate and transaction terms, ensuring that when you
execute the Transfer, you get exactly what was quoted.
## Core Components of a Transfer
When you create or retrieve a Transfer, the response contains several important components:
### Transfer Identification
* **`id`**: The unique identifier for the transfer (e.g., `TRF_abc123xyz`)
* **`quote_id`**: Reference to the Quote that defined the terms of this transfer
* **`reference`**: An additional reference identifier for tracking
* **`profile_id`**: The ID of the profile (business or customer) that owns this transfer
### Asset Details
* **`source_currency`**: The currency being sent (e.g., BTC, NGN)
* **`target_currency`**: The currency being received (e.g., USD, BTC)
* **`source_amount`**: The amount of source currency being transferred
* **`target_amount`**: The amount of target currency being received
* **`trade`**: The type of trade (`buy` or `sell`)
### Transfer Channels (`pay_in` and `pay_out`)
The `pay_in` and `pay_out` objects specify how assets move into and out of the transfer:
#### `pay_in` - Where the source assets come from
* Account balance
* Cryptocurrency address
* Bank account (temporary or permanent)
* Mobile money account
#### `pay_out` - Where the target assets go to
* Account balance
* Cryptocurrency address
* Bank account
* Mobile money account
These objects contain detailed information including addresses, account numbers, blockchain hashes (for crypto), and expiration times (for temporary accounts).
### Rate and Fees
* **`rate`**: The exchange rate object showing the conversion rate used, which currency pair, and the rate type (FIXED/FLOATING)
* **`fees`**: An array of fee objects detailing any charges applied to the transfer
### Status and Timeline
* **`status`**: The current status of the transfer (e.g., `pending`, `processing`, `completed`, `funds_refunded`)
* **`timeline`**: A detailed object showing the transfer's progress through various stages
* **`status_description`**: A human-readable description of the current status
## Transfer Status Lifecycle
Understanding the different statuses of your transfers helps you keep track of your funds and provide accurate information to your users. Here's a concise, tabulated view of what each status means:
Status
Code
Description
Final for
Pending
pending
Transfer initiated; funds not yet received. Waiting for assets to
arrive.
—
Processing
processing
Funds received and being handled; progressing to the next stage.
—
Cancelled
cancelled
Transfer cancelled (e.g., user cancelled, quote expired, validation
failed); will not proceed.
—
Completed
completed
Transfer fully processed and finalized; assets reached their
destination.
—
Funds Received
funds\_received
Payment successfully received for a deposit. Often the terminal step for
simple deposits.
Deposits
Funds Converted
funds\_converted
Currency conversion completed (e.g., NGN→BTC, BTC→USD). Terminal for
balance-to-balance conversions.
Conversions
Outgoing Payment Sent
outgoing\_payment\_sent
Payment initiated and sent on our end; funds are en route to the
destination.
—
Funds Delivered
funds\_delivered
Funds reached the destination. Typically the final step for payouts and
withdrawals.
Payouts/Withdrawals
## Transfer Completion Flow
Different types of transfers follow different paths through the status lifecycle. Here's how each type typically progresses:
### Deposits
A deposit will typically follow this flow and stop at **Funds Received**:
Deposit Flow for Busha Transfer
### Conversions
A conversion will conclude with **Funds Converted** as its final status:
Conversion Flow from currency to currency
### Payouts / Withdrawals
A payout or withdrawal will reach its final status at **Funds Delivered**:
Withdrawal Flow on Busha
## Transfer Timeline
Every Transfer includes a `timeline` object that provides detailed insight into the transfer's progress. This object contains:
* **`total_steps`**: The total number of steps this transfer will go through
* **`current_step`**: Which step the transfer is currently on
* **`transfer_status`**: The current high-level status
* **`events`**: An array of timeline events showing the history of the transfer
Each event in the timeline includes:
* **`step`**: The step number
* **`done`**: Whether this step is completed
* **`status`**: The status at this step
* **`title`**: A short title for the step
* **`description`**: A detailed description of what happened
* **`timestamp`**: When this event occurred
This timeline is invaluable for providing detailed status updates to your users and for debugging any issues with transfers.
## Best Practices for Working with Transfers
### 1. Always Create a Quote First
Never attempt to move assets without first creating a Quote. The Quote ensures:
* Rate certainty for your users
* Fee transparency
* Validation that the transfer is possible
* Protection against rate fluctuations during user confirmation
### 2. Check Quote Expiration
Always check the `expires_at` field of your Quote and create the Transfer before it expires. If a Quote expires, create a new one with current rates.
### 3. Monitor Transfer Status
Use webhooks or polling to monitor transfer status and provide real-time updates to your users. The `timeline` object provides detailed progress information.
### 4. Handle Failures Gracefully
Transfers can fail for various reasons (insufficient funds, invalid accounts, network issues). Always check the transfer status and `status_description` for error details, and provide clear feedback to users.
### 5. Store Transfer IDs
Always store the Transfer ID returned when you create a transfer. You'll need this ID to:
* Check transfer status
* Provide support
* Reconcile transactions
* Generate reports