Documentation Index
Fetch the complete documentation index at: https://kraken-sandbox.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
This guide walks you through enabling crypto deposits and withdrawals for your users via the Payward Embed API.
Prerequisites
Only cryptocurrency deposits are supported. Fiat deposits are not available through the Embed API.
Crypto deposits
Deposit workflow
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ List Deposit │──▶ │ Create Deposit │──▶ │ Display Address │──▶ │ User Sends │──▶ │ Receive │
│ Methods │ │ Address │ │ to User │ │ Crypto │ │ Webhooks │
└──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘
GET /funds/deposits/ POST /funds/deposits/ GET /funds/deposits/ (external wallet) deposit.
methods/{asset} addresses addresses status_updated
- List Deposit Methods: Query available networks, fees, and limits for an asset.
- Create Deposit Address: Generate an address for the chosen method.
- Display Address to User: Show the address (and any tag/memo) so the user can send crypto from an external wallet.
- Deposit to Address: Instruct the user to send crypto from their external wallet to the displayed deposit address. Ensure they include any required tag or memo.
- Receive Webhooks: Get notified via
deposit.status_updated when the deposit is processed.
Completed deposits will appear in GET /b2b/portfolio/transactions?user={iiban}&types=deposit.
Step 1: List deposit methods
Query available deposit methods for a crypto asset. Use the method_id from the response when creating an address in Step 2.
Most cryptocurrency deposits are free, with minimum deposit amounts varying by asset. A few cryptocurrencies are charged an address_setup_fee (a one-time fee on the user’s first deposit to a new address) or a per-deposit fee. See Cryptocurrency deposit fees and minimums for a full breakdown.
def list_deposit_methods(user_id, asset):
endpoint = f"/b2b/funds/deposits/methods/{asset}"
nonce = int(time.time() * 1000000000)
params = {"user": user_id}
signature = get_payward_signature(endpoint, None, API_SECRET, nonce, params)
headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
}
response = requests.get(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
)
return response.json()
methods = list_deposit_methods(user_id, "BTC")
for m in methods["result"]["methods"]:
print(f"{m['network']} (method_id: {m['method_id']})")
async function listDepositMethods(userId, asset) {
const endpoint = `/b2b/funds/deposits/methods/${asset}`;
const nonce = Date.now() * 1000000;
const params = { user: userId };
const signature = getPaywardSignature(endpoint, null, API_SECRET, nonce, params);
const url = `${BASE_URL}${endpoint}?user=${userId}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'API-Key': API_KEY,
'API-Sign': signature,
'API-Nonce': String(nonce),
},
});
return response.json();
}
const methods = await listDepositMethods(userId, 'BTC');
for (const m of methods.result.methods) {
console.log(`${m.network} (method_id: ${m.method_id})`);
}
Response example
{
"result": {
"methods": [
{
"method_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"network": "Bitcoin",
"fee": { "asset": "BTC", "amount": "0.00000000" },
"fee_percentage": "0.00",
"minimum": { "asset": "BTC", "amount": "0.00010000" },
"maximum": { "asset": "BTC", "amount": "100.00000000" },
"address_setup_fee": { "asset": "BTC", "amount": "0.00000000" },
"network_info": {
"explorer": "https://blockchair.com/bitcoin",
"confirmations": "3",
"est_confirmation_time": "45"
}
}
]
}
}
Key fields to display to users: network, fee, minimum, and est_confirmation_time.
Step 2: Create a deposit address
Generate a deposit address using the method_id from Step 1. Display the address to the user so they can send crypto from an external wallet.
def create_deposit_address(user_id, asset, method_id):
endpoint = "/b2b/funds/deposits/addresses"
nonce = int(time.time() * 1000000000)
body = {
"asset": asset,
"method_id": method_id,
}
params = {"user": user_id}
signature = get_payward_signature(endpoint, body, API_SECRET, nonce, params)
headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
"Content-Type": "application/json",
}
response = requests.post(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
json=body,
)
return response.json()
address = create_deposit_address(
user_id, "BTC", "3fa85f64-5717-4562-b3fc-2c963f66afa6"
)
print(f"Deposit address: {address['result']['address']}")
async function createDepositAddress(userId, asset, methodId) {
const endpoint = '/b2b/funds/deposits/addresses';
const nonce = Date.now() * 1000000;
const body = {
asset: asset,
method_id: methodId,
};
const params = { user: userId };
const signature = getPaywardSignature(endpoint, body, API_SECRET, nonce, params);
const url = `${BASE_URL}${endpoint}?user=${userId}`;
const response = await fetch(url, {
method: 'POST',
headers: {
'API-Key': API_KEY,
'API-Sign': signature,
'API-Nonce': String(nonce),
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
return response.json();
}
const address = await createDepositAddress(
userId, 'BTC', '3fa85f64-5717-4562-b3fc-2c963f66afa6'
);
console.log('Deposit address:', address.result.address);
Response example
{
"result": {
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"name": "Bitcoin",
"tag": null,
"memo": null,
"expire_time": null,
"is_new": true
}
}
Some networks (e.g., XRP, XLM) require a tag or memo in addition to the address. If tag or memo is present in the response, your UI must display it and instruct the user to include it when sending funds. Deposits sent without the required tag/memo may be lost.
Step 3: List deposit addresses
Retrieve existing deposit addresses for a given asset and method. Use this to display previously generated addresses to users without creating new ones each time.
def list_deposit_addresses(user_id, asset, method_id, cursor=None):
endpoint = "/b2b/funds/deposits/addresses"
nonce = int(time.time() * 1000000000)
params = {
"user": user_id,
"asset": asset,
"method_id": method_id,
}
if cursor:
params["cursor"] = cursor
signature = get_payward_signature(endpoint, None, API_SECRET, nonce, params)
headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
}
response = requests.get(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
)
return response.json()
addresses = list_deposit_addresses(
user_id, "BTC", "3fa85f64-5717-4562-b3fc-2c963f66afa6"
)
for addr in addresses["result"]["addresses"]:
print(f"Address: {addr['address']}")
async function listDepositAddresses(userId, asset, methodId, cursor = null) {
const endpoint = '/b2b/funds/deposits/addresses';
const nonce = Date.now() * 1000000;
const params = { user: userId, asset, method_id: methodId };
if (cursor) params.cursor = cursor;
const signature = getPaywardSignature(endpoint, null, API_SECRET, nonce, params);
const searchParams = new URLSearchParams(params);
const url = `${BASE_URL}${endpoint}?${searchParams.toString()}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'API-Key': API_KEY,
'API-Sign': signature,
'API-Nonce': String(nonce),
},
});
return response.json();
}
const addresses = await listDepositAddresses(
userId, 'BTC', '3fa85f64-5717-4562-b3fc-2c963f66afa6'
);
for (const addr of addresses.result.addresses) {
console.log('Address:', addr.address);
}
Response example
{
"result": {
"addresses": [
{
"address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"tag": null,
"memo": null,
"method_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"asset": "BTC",
"fee": { "asset": "BTC", "amount": "0.00000000" },
"minimum": { "asset": "BTC", "amount": "0.00010000" },
"maximum": { "asset": "BTC", "amount": "100.00000000" },
"expire_time": null,
"last_deposit_at": null
}
],
"next_cursor": null
}
}
Recommended UI flow
Best practices
- Always display tag/memo: For networks that require a tag or memo (XRP, XLM, etc.), prominently display it alongside the address. Missing tags/memos can result in lost funds.
- Set expectations: Show
minimum amounts and est_confirmation_time from the methods response so users know what to expect before sending funds.
- Use fresh responses: Available methods, addresses and limits are user-specific and may change based on account standing, remaining limits, or regional regulations. Fetch fresh data before displaying options rather than relying on cached results.
Crypto withdrawals
Crypto withdrawal support via the Embed API is coming soon. This section will be updated when available.
Statuses
| Status | Description |
|---|
pending | Detected and being processed |
held | Held for review |
success | Funds credited |
failure | Failed (terminal) |
Error handling
| Error | Cause | Solution |
|---|
ENexus:Unknown asset | Asset not recognized | Verify the asset code (e.g., BTC, ETH) |
EGeneral:Bad data | Invalid method_id or malformed request | Use a valid method_id from the list methods response |
EFunding:Too many addresses | Address limit reached for this method | Reuse an existing address via GET /b2b/funds/deposits/addresses |
API reference
| Endpoint | Method | Description |
|---|
/b2b/funds/deposits/methods/{asset} | GET | List deposit methods for an asset |
/b2b/funds/deposits/addresses | POST | Create a new deposit address |
/b2b/funds/deposits/addresses | GET | List existing deposit addresses |
/b2b/webhooks | POST | Register for deposit.status_updated webhooks |