Create a sandbox deposit
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <x-api-key>' \
--data '
{
"funding_account_id": "<string>",
"funding_account_scope": "<string>",
"currency": "<string>",
"amount": "<string>",
"scenario": "<string>",
"payout_scenario": "<string>",
"bridge_id": "<string>",
"deposit_id": "<string>",
"asset": "<string>",
"chain": "<string>"
}
'import requests
url = "https://api.sandbox.daya.co/v1/sandbox/deposits"
payload = {
"funding_account_id": "<string>",
"funding_account_scope": "<string>",
"currency": "<string>",
"amount": "<string>",
"scenario": "<string>",
"payout_scenario": "<string>",
"bridge_id": "<string>",
"deposit_id": "<string>",
"asset": "<string>",
"chain": "<string>"
}
headers = {
"X-Api-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
funding_account_id: '<string>',
funding_account_scope: '<string>',
currency: '<string>',
amount: '<string>',
scenario: '<string>',
payout_scenario: '<string>',
bridge_id: '<string>',
deposit_id: '<string>',
asset: '<string>',
chain: '<string>'
})
};
fetch('https://api.sandbox.daya.co/v1/sandbox/deposits', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.daya.co/v1/sandbox/deposits",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'funding_account_id' => '<string>',
'funding_account_scope' => '<string>',
'currency' => '<string>',
'amount' => '<string>',
'scenario' => '<string>',
'payout_scenario' => '<string>',
'bridge_id' => '<string>',
'deposit_id' => '<string>',
'asset' => '<string>',
'chain' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.daya.co/v1/sandbox/deposits"
payload := strings.NewReader("{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.daya.co/v1/sandbox/deposits")
.header("X-Api-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.daya.co/v1/sandbox/deposits")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyDeposits
Create a sandbox deposit
Simulate customer funding, merchant funding, or bridge deposits in sandbox
POST
/
v1
/
sandbox
/
deposits
Create a sandbox deposit
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <x-api-key>' \
--data '
{
"funding_account_id": "<string>",
"funding_account_scope": "<string>",
"currency": "<string>",
"amount": "<string>",
"scenario": "<string>",
"payout_scenario": "<string>",
"bridge_id": "<string>",
"deposit_id": "<string>",
"asset": "<string>",
"chain": "<string>"
}
'import requests
url = "https://api.sandbox.daya.co/v1/sandbox/deposits"
payload = {
"funding_account_id": "<string>",
"funding_account_scope": "<string>",
"currency": "<string>",
"amount": "<string>",
"scenario": "<string>",
"payout_scenario": "<string>",
"bridge_id": "<string>",
"deposit_id": "<string>",
"asset": "<string>",
"chain": "<string>"
}
headers = {
"X-Api-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
funding_account_id: '<string>',
funding_account_scope: '<string>',
currency: '<string>',
amount: '<string>',
scenario: '<string>',
payout_scenario: '<string>',
bridge_id: '<string>',
deposit_id: '<string>',
asset: '<string>',
chain: '<string>'
})
};
fetch('https://api.sandbox.daya.co/v1/sandbox/deposits', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.daya.co/v1/sandbox/deposits",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'funding_account_id' => '<string>',
'funding_account_scope' => '<string>',
'currency' => '<string>',
'amount' => '<string>',
'scenario' => '<string>',
'payout_scenario' => '<string>',
'bridge_id' => '<string>',
'deposit_id' => '<string>',
'asset' => '<string>',
'chain' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.daya.co/v1/sandbox/deposits"
payload := strings.NewReader("{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.daya.co/v1/sandbox/deposits")
.header("X-Api-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.daya.co/v1/sandbox/deposits")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"funding_account_id\": \"<string>\",\n \"funding_account_scope\": \"<string>\",\n \"currency\": \"<string>\",\n \"amount\": \"<string>\",\n \"scenario\": \"<string>\",\n \"payout_scenario\": \"<string>\",\n \"bridge_id\": \"<string>\",\n \"deposit_id\": \"<string>\",\n \"asset\": \"<string>\",\n \"chain\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyOverview
This sandbox-only endpoint creates a mock deposit for an existing customer or merchant funding account, or creates or advances a bridge simulation. Setfunding_account_scope to select the type of simulation:
BRIDGE: Creates a bridge receipt or advances its simulated payout or refund. Usebridge_id, notfunding_account_id. See Bridge simulations.CUSTOMER(default): Runs the simulated deposit through the customer funding-account settlement and webhook flow.MERCHANT: Creates a merchant funding deposit. Includecurrency: NGNandamountto credit a specific amount towithdrawal_balance_ngn. Includecurrency: USDand an optionalamountto creditwithdrawal_balance_usd. Omitting both preserves the legacy 10 USD simulation.
- Deposit creation
- Settlement to internal balance, onchain payout, or NGN payout
- Webhook dispatch
scenario to trigger a specific sandbox lifecycle outcome. Use scenarios when you need to confirm your app handles specific deposit states without waiting for the sandbox processor to produce them naturally.
For a customer funding account, create the receive instruction with /v1/funding-accounts, then pass its id. For merchant funding, call GET /v1/merchant/funding, pass data.id, and set funding_account_scope to MERCHANT.
This endpoint is available only in sandbox. Calls outside sandbox return
403 or 404.For end-to-end guidance (recommended flow, what to validate, and common flagging scenarios), see Sandbox testing.
Authentication
string
required
Your merchant API key
string
Required when
funding_account_scope is MERCHANT or BRIDGE. Use a unique value for each simulated deposit and reuse the same value when retrying that request. Retries with the same value resume the original deposit instead of creating another. Bridge advances keep the same deposit ID; see the behavior below.Request Body
string
Required for
CUSTOMER and MERCHANT; omit for BRIDGE. Funding account ID to simulate a deposit for. For customer funding, use the id returned by /v1/funding-accounts. For merchant funding, use data.id from GET /v1/merchant/funding.Example: 6b0e8400-e29b-41d4-a716-446655440000string
default:"CUSTOMER"
Selects the funding account kind. Allowed values are
CUSTOMER, MERCHANT, and BRIDGE. Omit this field for existing customer funding-account simulations.string
Merchant funding simulations only. Allowed values are
NGN and USD. NGN credits withdrawal_balance_ngn; USD credits withdrawal_balance_usd. Omit this field to preserve the legacy USD simulation.string
For
MERCHANT, a positive decimal amount in the selected currency. Required when currency is NGN; optional for USD, which defaults to 10 when omitted. NGN supports at most two decimal places and USD supports at most six. For a BRIDGE create, this is an optional positive decimal string with at most six digits before and after the point; it defaults to the bridge estimate and can test below-minimum or over-limit receipts. Omit it on advance. CUSTOMER does not accept this field.string
Optional sandbox lifecycle outcome to trigger.
CUSTOMER and MERCHANT values:DEFAULTPROCESSINGCOMPLETEDREQUIRES_REVIEWFAILED
BRIDGE, use the additional scenarios below; its default leaves the payout waiting.string
Optional linked payout outcome for customer funding accounts. Allowed values are
DEFAULT, PROCESSING, SETTLED, and FAILED. This field is supported only when funding_account_scope is CUSTOMER.string
Required UUID for
BRIDGE. Must identify your sandbox bridge request.string
BRIDGE advance only. The existing deposit must belong to your merchant and the named sandbox bridge. Omit to create a receipt.string
BRIDGE create only. USDT or USDC; defaults to the request asset. WRONG_ASSET defaults to the other stablecoin.string
BRIDGE create only. POLYGON, BSC, SOLANA, or APTOS; defaults to the request’s deposit chain. WRONG_CHAIN defaults to its destination chain.Request Examples
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_id": "6b0e8400-e29b-41d4-a716-446655440000"
}'
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_id": "6b0e8400-e29b-41d4-a716-446655440000",
"scenario": "COMPLETED"
}'
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_id": "6b0e8400-e29b-41d4-a716-446655440000",
"scenario": "REQUIRES_REVIEW"
}'
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'X-Idempotency-Key: merchant-deposit-test-001' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_id": "750e8400-e29b-41d4-a716-446655440000",
"funding_account_scope": "MERCHANT",
"scenario": "COMPLETED"
}'
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'X-Idempotency-Key: merchant-ngn-deposit-test-001' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_id": "750e8400-e29b-41d4-a716-446655440000",
"funding_account_scope": "MERCHANT",
"currency": "NGN",
"amount": "10000",
"scenario": "COMPLETED"
}'
Response
Returns a confirmation message and the simulated deposit status. For customer funding accounts, use/v1/deposits and webhook events to track the deposit.
message: Human-readable status messagedeposit_id: Created deposit IDstatus: Current deposit statusscenario: Scenario that was applied, if provided
{
"message": "Sandbox deposit created for processing.",
"deposit_id": "4b4a0f1f-f1dc-4f4c-a77d-3f4ebc8b4f42",
"status": "COMPLETED",
"scenario": "COMPLETED"
}
Customer funding lifecycle outcomes
Usescenario to test the state machine in your integration:
| Scenario | Expected webhook path | Use this to test |
|---|---|---|
PROCESSING | deposit.received → deposit.processing | In-progress UI and retry-safe polling |
COMPLETED | deposit.received → deposit.completed | Crediting/final success logic |
REQUIRES_REVIEW | deposit.received → deposit.requires_review | Review/hold states |
FAILED | deposit.received → deposit.failed | Failure messaging and recovery |
Scenario outcomes are for testing a specific lifecycle state in sandbox.
PROCESSING and COMPLETED still use the funding account’s active settlement destination, so the funding account must include any required rate_id, destination wallet, or destination bank details. To test the production-like settlement processor and any natural intermediate states, omit scenario.Merchant funding outcomes
Merchant funding simulations do not use the customer settlement destination orpayout_scenario. An NGN simulation directly credits the merchant’s NGN withdrawal balance and requires an active sandbox NGN merchant funding account.
| Scenario | Returned status | Merchant balance |
|---|---|---|
Omitted or DEFAULT | SETTLED | Credits the requested merchant amount and currency; defaults to 10 USD when both are omitted |
PROCESSING | PENDING | No credit |
COMPLETED | SETTLED | Credits the requested merchant amount and currency; defaults to 10 USD when both are omitted |
REQUIRES_REVIEW | FLAGGED | No credit |
FAILED | FAILED | No credit |
Bridge simulations
First create a sandbox bridge withtype: TEMPORARY and asset: USDT. Bridge simulations require both write and withdraw scopes. Send X-Idempotency-Key for each request. Use the bridge chain list; all payouts and refunds on this endpoint are simulated.
For create, send funding_account_scope: BRIDGE, bridge_id, and optionally amount, asset, chain, and scenario. For advance, send only the scope, bridge_id, deposit_id, and scenario. Do not send funding_account_id, currency, or payout_scenario for either bridge operation.
Create a processing bridge deposit
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'X-Idempotency-Key: bridge-receipt-001' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_scope": "BRIDGE",
"bridge_id": "750e8400-e29b-41d4-a716-446655440000",
"amount": "500",
"asset": "USDT",
"chain": "POLYGON",
"scenario": "PROCESSING"
}'
202 response for an eligible deposit:
{
"message": "Sandbox deposit created for processing.",
"deposit_id": "850e8400-e29b-41d4-a716-446655440000",
"status": "PROCESSING",
"scenario": "PROCESSING"
}
Advance that deposit
curl --request POST \
--url https://api.sandbox.daya.co/v1/sandbox/deposits \
--header 'X-Api-Key: YOUR_SANDBOX_KEY' \
--header 'X-Idempotency-Key: bridge-advance-001' \
--header 'Content-Type: application/json' \
--data '{
"funding_account_scope": "BRIDGE",
"bridge_id": "750e8400-e29b-41d4-a716-446655440000",
"deposit_id": "850e8400-e29b-41d4-a716-446655440000",
"scenario": "COMPLETED"
}'
202, message Sandbox deposit advanced., the same deposit_id, and the current status and selected scenario. An omitted or DEFAULT scenario is omitted from the response. 202 means the simulation was handled; read its status rather than assuming success.
Scenarios follow the amount and timing rules. A deposit that needs review stays in review, even when COMPLETED is requested.
| Scenario | Result |
|---|---|
Omitted, DEFAULT, PROCESSING | Leave the deposit in PROCESSING. |
WAITING_FOR_LIQUIDITY | Leave the payout waiting for funds. |
COMPLETED | Complete the simulated payout. |
REQUIRES_REVIEW | Return a deposit that needs review. |
FAILED | Return a failed payout. |
UNCERTAIN_PAYOUT | Simulate an unknown send outcome; requires review. |
LATE | Test a receipt classified as late. If the simulation returns 409, retry the same request later. A successful simulation holds the receipt for review. |
WRONG_ASSET | Simulate a payment in the other stablecoin; returns REQUIRES_REVIEW without deposit_id. |
WRONG_CHAIN | Simulate a payment on another chain; returns REQUIRES_REVIEW without deposit_id. |
REFUNDED | Complete a simulated refund. Requires a deposit with a refund already in progress. |
REFUNDED, contact support@daya.co to prepare a deposit with a refund in progress.
Advance a PROCESSING deposit to COMPLETED, FAILED, or UNCERTAIN_PAYOUT. Repeating an applied outcome returns the current state. Invalid transitions return 409 without changing the deposit.
Use a unique key for every new simulated deposit, even when repeating a test later. Retry with the same key and body to avoid a duplicate deposit. Changing receipt details or the scenario under a create key returns 409. When advancing, keep the same deposit ID on retries. Responses show the current state rather than a replay of an earlier response.
Track results through bridge deposits and bridge events.
Error Responses
This endpoint may return:400: Invalid request401: Unauthorized403: Missing required scope, restricted access, or not available outside sandbox404: Funding account, bridge request, or deposit not found; endpoint unavailable outside sandbox409: Invalid transition or conflicting simulation503: Bridge simulation temporarily unavailable500: Internal server error
Next Steps
Get merchant funding
Get the merchant funding account ID and Base address
Webhooks Overview
Verify your webhook handling with sandbox events
Sandbox testing
Recommended end-to-end sandbox flow + common flagging scenarios