| Direct FX | Pan-African Ramp | |
|---|---|---|
| Currencies | NGN | NGN, GHS, KES, SLE, ZAR, UGX, ZMW, XAF |
| Endpoint | POST /transactions/v2/onramp | POST /transactions/v2/direct_ramp/deposit |
| Quote first? | No | Yes — the deposit needs a quoteId |
| Settlement | Manual: the user pays LINK’s account, LINK confirms | Automated through local rails |
- Direct FX
- Pan-African Ramp
Initiate a buy transaction
POST /transactions/v2/onramp
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
currency | string | ✓ | Fiat the user pays in: NGN |
amount | string | ✓ | Amount in that fiat currency |
stables | string | ✓ | Stablecoin to deliver, e.g. USDC |
wallet_address | string | ✓ | Where the stablecoin is sent |
network | string | ✓ | Chain for the payout, e.g. Base |
addMarkUp | boolean | Apply your developer markup to this transaction | |
markupPercentage | number | Markup to apply, up to 2% |
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'ngnc-sec-key': 'YOUR_SECRET_KEY',
'content-type': 'application/json'
},
body: JSON.stringify({
currency: 'NGN',
amount: '500000',
stables: 'USDC',
wallet_address: '0x3f1e...a92c',
network: 'Base'
})
};
fetch('https://api.linkio.world/transactions/v2/onramp', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
import requests
url = "https://api.linkio.world/transactions/v2/onramp"
payload = {
"currency": "NGN",
"amount": "500000",
"stables": "USDC",
"wallet_address": "0x3f1e...a92c",
"network": "Base"
}
headers = {
"accept": "application/json",
"ngnc-sec-key": "YOUR_SECRET_KEY",
"content-type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)
Response
201 Created{
"code": "TXN_SUCCESSFUL",
"status": "Success",
"message": "Transaction Request Successful",
"transaction": {
"transaction_id": "66f2a1c8e4b0f3a7d1c9e5b2",
"business": {
"business_id": "0847363729"
},
"reference": "ret-mukgw7ax-nmw4wd",
"type": "Buy",
"onramp_rate": 1587.9,
"amount": "500000 NGN",
"payout_amount": "314.88 USDC",
"transaction_status": "Pending",
"link_account_name": "LINK GLOBAL",
"link_account_number": "8180789670",
"link_bank_name": "Wema Bank",
"wallet_address": "0x3f1e...a92c",
"network": "Base",
"date_created": "October 03, 2026 14:22"
}
}
Show
link_account_name, link_account_number and link_bank_name to your user — that is the account they pay into. The transaction stays Pending until LINK confirms the deposit, then a webhook reports the change.Step 1 — Get a quote
GET /transactions/v2/direct_ramp/rate_quote
quoteId, so always quote first. Quotes are valid for 120 seconds. See Retail Rates for the full parameters.Step 2 — Initiate the deposit
POST /transactions/v2/direct_ramp/deposit
| Parameter | Type | Required | Description |
|---|---|---|---|
quoteId | string | ✓ | From the quote in step 1 |
address | string | ✓ | Wallet that receives the stablecoin |
network | string | ✓ | Chain for the payout |
phone_number | string | Customer’s phone number | |
bankaccount_number | string | Customer’s bank account number |
const params = new URLSearchParams({
quoteId: 'ba7f1d2c-9e44-4c0b-9a3f-2b7c5d8e1a66',
address: '0x3f1e...a92c',
network: 'Base'
});
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'ngnc-sec-key': 'YOUR_SECRET_KEY'
}
};
fetch(`https://api.linkio.world/transactions/v2/direct_ramp/deposit?${params}`, options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
import requests
url = "https://api.linkio.world/transactions/v2/direct_ramp/deposit"
params = {
"quoteId": "ba7f1d2c-9e44-4c0b-9a3f-2b7c5d8e1a66",
"address": "0x3f1e...a92c",
"network": "Base"
}
headers = {
"accept": "application/json",
"ngnc-sec-key": "YOUR_SECRET_KEY"
}
response = requests.post(url, params=params, headers=headers)
print(response.text)
Response
200 OK{
"status": "Pending",
"message": "Request created. Send NGN to details provided and confirm transaction with reference.",
"data": {
"ticketId": "c91f4e7a-55b2-4c8d-8f1e-3a6b9d2c7e40",
"reference": "par-mukgw7ax-nmw4wd",
"sourceAsset": "NGN",
"amount": 500000,
"rate": 1587.9,
"payoutAsset": "USDC",
"payoutAmount": 314.88,
"vendorDetails": "Wema Bank 8180789670 LINK GLOBAL",
"status": "created",
"expiresAt": "2026-10-03T14:52:11Z",
"date": "2026-10-03 14:22"
}
}
vendorDetails is a single string, not an object — show it to the user as the payment instruction. The ticket expires at expiresAt; after that the user must start again with a fresh quote.Next steps
Both corridors report progress over webhooks, and the events differ per corridor.Retail Coverage Retail Off-Ramp

