Retrieve rates
curl --request GET \
--url https://api.daya.co/v1/rates \
--header 'X-Api-Key: <x-api-key>'import requests
url = "https://api.daya.co/v1/rates"
headers = {"X-Api-Key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<x-api-key>'}};
fetch('https://api.daya.co/v1/rates', 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.daya.co/v1/rates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.daya.co/v1/rates"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.daya.co/v1/rates")
.header("X-Api-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.daya.co/v1/rates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"rate_id": "rate_8x7k2mq9p",
"from": "NGN",
"to": "USDC",
"side": "BUY",
"rate": 1545.50,
"inverse_rate": 0.000647,
"fee_bps": 50,
"min_deposit_ngn": 1500.00,
"created_at": "2026-01-14T15:05:00Z",
"expires_at": "2026-01-14T15:35:00Z"
}
Rates & Chains
Retrieve rates
Get current exchange rates for NGN to USDC/USDT conversions
GET
/
v1
/
rates
Retrieve rates
curl --request GET \
--url https://api.daya.co/v1/rates \
--header 'X-Api-Key: <x-api-key>'import requests
url = "https://api.daya.co/v1/rates"
headers = {"X-Api-Key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<x-api-key>'}};
fetch('https://api.daya.co/v1/rates', 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.daya.co/v1/rates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://api.daya.co/v1/rates"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.daya.co/v1/rates")
.header("X-Api-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.daya.co/v1/rates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"rate_id": "rate_8x7k2mq9p",
"from": "NGN",
"to": "USDC",
"side": "BUY",
"rate": 1545.50,
"inverse_rate": 0.000647,
"fee_bps": 50,
"min_deposit_ngn": 1500.00,
"created_at": "2026-01-14T15:05:00Z",
"expires_at": "2026-01-14T15:35:00Z"
}
Overview
Request firm FX quotes with guaranteed exchange rates. Each rate has a ~30-minute validity window and is identified by a uniquerate_id.
Authentication
string
required
Your merchant API key
X-Api-Key: YOUR_API_KEY
Query Parameters
string
required
Source currency. Currently only
NGN is supported.Allowed values: NGNstring
required
Destination currency.Allowed values:
USDC, USDT, USDUSD is treated as equivalent to USDC/USDT in v0.1. Depeg scenarios are not handled.string
required
Rate side. Determines whether the quote is for buying or selling crypto.Allowed values:
BUY, SELLBUY— Merchant is buying crypto (NGN deposits → stablecoin). Use for NGN funding accounts that settle onchain.SELL— Merchant is selling crypto (stablecoin → NGN). Use for crypto funding accounts that settle to an NGN bank account.
Request Examples
curl --request GET \
--url 'https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY' \
--header 'X-Api-Key: YOUR_API_KEY'
const response = await fetch(
'https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY',
{
headers: {
'X-Api-Key': 'YOUR_API_KEY'
}
}
);
const rate = await response.json();
console.log(rate);
import requests
response = requests.get(
'https://api.daya.co/v1/rates',
params={'from': 'NGN', 'to': 'USDC', 'side': 'BUY'},
headers={'X-Api-Key': 'YOUR_API_KEY'}
)
rate = response.json()
print(rate)
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
Response
string
required
Unique identifier for this rate snapshot. Use this when creating funding accounts that need a quoted conversion.Example:
rate_8x7k2mq9pstring
required
Source currencyExample:
NGNstring
required
Destination currencyExample:
USDCstring
required
Rate side —
BUY or SELLExample: BUYnumber
required
Conversion rate from source to destination (e.g., 1 USDC = X NGN)Example:
1545.50This rate already includes Daya’s spread/fee. You don’t need to calculate fees separately.
number
required
Inverse conversion rate (e.g., 1 NGN = X USDC)Example:
0.000647integer
Fee in basis points (1 bps = 0.01%)Example:
50 (0.5%)number
required
Minimum NGN deposit amount for this rateExample:
1500.00 (~$1.00)Deposits below this amount will be rejected with status
FAILED.string
required
When this rate was generated (ISO 8601 timestamp)Example:
2026-01-14T15:05:00Zstring
required
When this rate becomes invalid (ISO 8601 timestamp)Example:
2026-01-14T15:35:00ZAlways check this before using
rate_id to create a funding account. Expired rates will be rejected.Success Response
{
"rate_id": "rate_8x7k2mq9p",
"from": "NGN",
"to": "USDC",
"side": "BUY",
"rate": 1545.50,
"inverse_rate": 0.000647,
"fee_bps": 50,
"min_deposit_ngn": 1500.00,
"created_at": "2026-01-14T15:05:00Z",
"expires_at": "2026-01-14T15:35:00Z"
}
Error Responses
{
"error": {
"code": "missing_parameter",
"message": "Required parameter 'from' is missing",
"details": "Query parameter 'from' must be provided"
}
}
{
"error": {
"code": "invalid_currency",
"message": "Invalid currency specified",
"details": "Only NGN is supported for 'from' parameter"
}
}
{
"error": {
"code": "rate_unavailable",
"message": "No valid exchange rates available at this time",
"details": "Please try again in a few minutes"
}
}
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key"
}
}
Rate Lifecycle
New rates are generated approximately every 10 minutes and expire after ~30 minutes.Time Rate ID Valid Until
─────────────────────────────────────
15:05 rate_abc123 15:35
15:15 rate_def456 15:45
15:25 rate_ghi789 15:55
15:35 rate_jkl012 16:05
Request a fresh rate immediately before creating each temporary funding account that requires one. Every temporary NGN virtual account currently requires a BUY
rate_id, including NGN_BALANCE even though that settlement mode retains NGN without conversion.Usage Notes
Rate Guarantee
For temporary funding accounts with a quoted settlement destination, the rate is guaranteed for deposits within the validity window:- Funding account created with
rate_idat 15:10 - Rate expires at 15:35
- Deposit at 15:20 → Uses guaranteed rate ✅
- Deposit at 15:40 → Flagged (expired) ❌
Caching Rates
You can cache rates client-side but must respectexpires_at:
class RateCache {
constructor() {
this.rate = null;
}
async getValidRate() {
if (!this.rate || new Date() >= new Date(this.rate.expires_at)) {
const response = await fetch('https://api.daya.co/v1/rates?from=NGN');
this.rate = await response.json();
}
return this.rate;
}
}
Checking Time Remaining
Calculate remaining validity time:function getSecondsRemaining(expiresAt) {
const now = new Date();
const expiry = new Date(expiresAt);
return Math.max(0, (expiry - now) / 1000);
}
const rate = await getRates();
const remaining = getSecondsRemaining(rate.expires_at);
console.log(`Rate valid for ${remaining} seconds`);
Rate Calculation
The displayed rate includes Daya’s fee:Displayed Rate = Market Rate × (1 - fee_bps / 10000)
- Market rate: 1550 NGN/USDC
- Fee: 50 bps (0.5%)
- Displayed rate: 1550 × (1 - 0.005) = 1545.50 NGN/USDC
Common Patterns
Get rate before funding account creation
Get rate before funding account creation
Recommended flow:
- Call
GET /v1/rates - Display rate to user
- User confirms
- Call
POST /v1/funding-accountswithrate_id
async function createFundingAccountWithRate(customerId, destinationAddress) {
// Step 1: Get current rate
const rate = await getRates();
// Step 2: Show to user (await confirmation)
await showRateToUser(rate);
// Step 3: Create funding account with rate_id
const fundingAccount = await createFundingAccount({
type: 'TEMPORARY',
rail: 'NGN_VIRTUAL_ACCOUNT',
customer: { customer_id: customerId },
currency: 'NGN',
amount: 50000,
settlement_destination: {
type: 'ONCHAIN',
rate_id: rate.rate_id,
destination_asset: 'USDC',
destination_chain: 'BASE',
destination_address: destinationAddress
}
});
return fundingAccount;
}
Handle rate unavailability
Handle rate unavailability
If FX venue is down, gracefully handle
rate_unavailable error:async function getRatesWithRetry(maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch('https://api.daya.co/v1/rates?from=NGN');
if (response.status === 503) {
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
continue;
}
return await response.json();
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
throw new Error('Rates unavailable after retries');
}
Rate Limits
- 100 requests per minute per API key
- No specific rate limit on this endpoint (non-mutating)
Next Steps
Create Funding Account
Use the rate_id to create a funding account
Rates Concept
Learn more about rate semantics