OKX Onchain Gateway API
6 endpoints for gas estimation, transaction simulation, broadcasting, and order tracking.
Base paths:
/api/v6/dex/pre-transaction
and
/api/v6/dex/post-transaction
Auth: HMAC-SHA256 signature, 4 headers required (
,
,
,
)
Note: Endpoints #1-2 are GET requests, endpoints #3-5 are POST requests, endpoint #6 is GET.
Authentication & Credentials
API Key Application:
OKX Developer Portal
Read credentials from environment variables:
- → API key
- → Secret key (system-generated)
- → Passphrase (developer-supplied)
Never output the above credentials to logs, response content, or any user-visible interface.
typescript
import crypto from 'crypto';
const BASE = 'https://web3.okx.com';
// Signature rule:
// GET → body = "", requestPath includes query string (e.g., "/api/v6/dex/pre-transaction/gas-price?chainIndex=1")
// POST → body = JSON string of request body, requestPath is path only (e.g., "/api/v6/dex/pre-transaction/gas-limit")
// Note: Endpoints #1-2, #6 are GET; endpoints #3-5 are POST
async function okxFetch(method: 'GET' | 'POST', path: string, body?: object) {
const timestamp = new Date().toISOString();
const bodyStr = body ? JSON.stringify(body) : '';
const sign = crypto
.createHmac('sha256', process.env.OKX_SECRET_KEY!)
.update(timestamp + method + path + bodyStr)
.digest('base64');
const headers: Record<string, string> = {
'OK-ACCESS-KEY': process.env.OKX_API_KEY!,
'OK-ACCESS-SIGN': sign,
'OK-ACCESS-PASSPHRASE': process.env.OKX_PASSPHRASE!,
'OK-ACCESS-TIMESTAMP': timestamp,
'Content-Type': 'application/json',
};
const res = await fetch(`${BASE}${path}`, {
method,
headers,
...(body && { body: bodyStr }),
});
if (res.status === 429) throw { code: 'RATE_LIMITED', msg: 'Rate limited — retry with backoff', retryable: true };
if (res.status >= 500) throw { code: `HTTP_${res.status}`, msg: 'Server error', retryable: true };
const json = await res.json();
if (json.code !== '0') throw { code: json.code, msg: json.msg || 'API error', retryable: false };
return json.data;
}
Response envelope:
{ "code": "0", "data": [...], "msg": "" }
.
=
means success.
Developer Quickstart
Get Gas Price
typescript
// Get current gas price on Ethereum
const gasPrice = await okxFetch('GET', '/api/v6/dex/pre-transaction/gas-price?' + new URLSearchParams({
chainIndex: '1',
}));
// → gasPrice[].normal, gasPrice[].min, gasPrice[].max (legacy)
// → gasPrice[].eip1559Protocol.suggestBaseFee, .proposePriorityFee (EIP-1559)
console.log(`Gas price: ${gasPrice[0].eip1559Protocol?.suggestBaseFee ?? gasPrice[0].normal} wei`);
Broadcast a Signed Transaction
typescript
// Broadcast a signed EVM transaction
const result = await okxFetch('POST', '/api/v6/dex/pre-transaction/broadcast-transaction', {
signedTx: '0xf86c...signed_hex',
chainIndex: '1',
address: '0xYourWallet',
});
// → result[].orderId — use with /post-transaction/orders to track
console.log(`Broadcast success, orderId: ${result[0].orderId}`);
Common Chain IDs
| Chain | chainIndex | Chain | chainIndex |
|---|
| Ethereum | | Arbitrum | |
| BSC | | Base | |
| Polygon | | Solana | |
Endpoint Index
Cross-Skill Workflows
This skill is the final mile — it takes a signed transaction and sends it on-chain. It pairs with swap (to get tx data) and balance (to verify funds).
Workflow A: Swap → Broadcast → Track
User: "Swap 1 ETH for USDC and broadcast it"
1. okx-dex-swap /aggregator/swap → get tx calldata { from, to, data, value, gas }
↓ user signs the tx locally
2. okx-onchain-gateway /pre-transaction/broadcast-transaction → broadcast signed tx → orderId
3. okx-onchain-gateway /post-transaction/orders → track order status until confirmed
Data handoff:
- , , , from swap → user builds & signs → for broadcast
- from broadcast → param in orders query
Workflow B: Simulate → Broadcast → Track
User: "Simulate this transaction first, then broadcast if safe"
1. okx-onchain-gateway /pre-transaction/simulate → check if tx will succeed
↓ simulation passes (no revert)
2. okx-onchain-gateway /pre-transaction/broadcast-transaction → broadcast signed tx
3. okx-onchain-gateway /post-transaction/orders → track order status
Workflow C: Balance Check → Swap → Broadcast
User: "Check if I have enough ETH, swap for USDC, then send it"
1. okx-wallet-portfolio /balance/token-balances-by-address → verify ETH balance
↓ sufficient balance confirmed
2. okx-dex-swap /aggregator/swap → get swap tx calldata
↓ user signs
3. okx-onchain-gateway /pre-transaction/broadcast-transaction → broadcast
4. okx-onchain-gateway /post-transaction/orders → track
Operation Flow
Step 1: Identify Intent
- Estimate gas for a chain →
GET /pre-transaction/gas-price
- Estimate gas limit for a specific tx →
POST /pre-transaction/gas-limit
- Test if a tx will succeed →
POST /pre-transaction/simulate
- Broadcast a signed tx →
POST /pre-transaction/broadcast-transaction
- Track a broadcast order →
GET /post-transaction/orders
- Check supported chains →
GET /pre-transaction/supported/chain
Step 2: Collect Parameters
- Missing → ask which chain
- Missing → remind user to sign the transaction first (this API does NOT sign)
- Missing wallet → ask user
- For gas-limit / simulate → need , , ,
- For orders query → need and , optionally
Step 3: Execute
- Gas estimation: call or , display results
- Simulation: call , check for revert or success
- Broadcast: call with signed tx, return
- Tracking: call , display order status
Step 4: Suggest Next Steps
After displaying results, suggest 2-3 relevant follow-up actions based on the endpoint just called:
| Just completed | Suggest |
|---|
/pre-transaction/gas-price
| 1. Estimate gas limit for a specific tx → /pre-transaction/gas-limit
(this skill) 2. Get a swap quote → 3. Check wallet balance → |
/pre-transaction/gas-limit
| 1. Simulate the transaction → /pre-transaction/simulate
(this skill) 2. Proceed to broadcast → /pre-transaction/broadcast-transaction
(this skill) |
/pre-transaction/simulate
| 1. Broadcast the transaction → /pre-transaction/broadcast-transaction
(this skill) 2. Adjust and re-simulate if failed → /pre-transaction/simulate
(this skill) |
/pre-transaction/broadcast-transaction
| 1. Track order status → (this skill) 2. Check updated wallet balance → |
| 1. Check wallet balance after confirmation → 2. View price of received token → 3. Execute another swap → |
Present conversationally, e.g.: "Transaction broadcast! Would you like to track the order status?" — never expose skill names or endpoint paths to the user.
API Reference
1. GET /pre-transaction/supported/chain
No request parameters.
Response:
| Field | Type | Description |
|---|
| String | Chain unique identifier (e.g., "1") |
| String | Chain name (e.g., "Ethereum") |
| String | Chain logo URL |
| String | Chain short name (e.g., "ETH") |
2. GET /pre-transaction/gas-price
| Param | Type | Required | Description |
|---|
| String | Yes | Chain ID (e.g., ) |
Response:
| Field | Type | Description |
|---|
| String | Normal gas price (legacy) |
| String | Minimum gas price |
| String | Maximum gas price |
| Boolean | Whether EIP-1559 is supported |
data[].eip1559Protocol.suggestBaseFee
| String | Suggested base fee |
data[].eip1559Protocol.baseFee
| String | Current base fee |
data[].eip1559Protocol.proposePriorityFee
| String | Proposed priority fee |
data[].eip1559Protocol.safePriorityFee
| String | Safe (slow) priority fee |
data[].eip1559Protocol.fastPriorityFee
| String | Fast priority fee |
For Solana chains, response includes:
,
,
,
.
json
{
"code": "0",
"data": [{
"normal": "20000000000",
"min": "15000000000",
"max": "30000000000",
"supporteip1559": true,
"eip1559Protocol": {
"suggestBaseFee": "18000000000",
"baseFee": "18000000000",
"proposePriorityFee": "2000000000",
"safePriorityFee": "1000000000",
"fastPriorityFee": "3000000000"
}
}],
"msg": ""
}
3. POST /pre-transaction/gas-limit
| Param | Type | Required | Description |
|---|
| String | Yes | Chain ID |
| String | Yes | Sender address |
| String | Yes | Recipient / contract address |
| String | No | Transfer value in minimal units (default "0") |
| Object | No | Extended parameters |
| String | No | Encoded calldata (for contract interactions) |
Response:
| Field | Type | Description |
|---|
| String | Estimated gas limit |
json
{
"code": "0",
"data": [{ "gasLimit": "21000" }],
"msg": ""
}
4. POST /pre-transaction/simulate
| Param | Type | Required | Description |
|---|
| String | Yes | Chain ID |
| String | Yes | Sender address |
| String | Yes | Recipient / contract address |
| String | No | Transfer value in minimal units |
| String | No | Gas price in wei (for legacy EVM txs) |
| String | No | Priority fee in micro-lamports (Solana only) |
| Object | Yes | Extended parameters |
| String | Yes | Encoded calldata |
Response:
| Field | Type | Description |
|---|
| String | Transaction intent description |
| Array | Asset changes from the simulation |
data[].assetChange[].assetType
| String | Asset type |
data[].assetChange[].name
| String | Token name |
data[].assetChange[].symbol
| String | Token symbol |
data[].assetChange[].decimals
| Number | Token decimals |
data[].assetChange[].address
| String | Token contract address |
data[].assetChange[].rawValue
| String | Raw amount change |
| String | Gas consumed in simulation |
| String | Failure reason (empty string = success) |
| Array | Risk information (address, addressType) |
json
{
"code": "0",
"data": [{
"intention": "Token Swap",
"assetChange": [{"assetType": "token", "name": "USDC", "symbol": "USDC", "decimals": 6, "address": "0xa0b8...", "rawValue": "-100000000"}],
"gasUsed": "145000",
"failReason": "",
"risks": []
}],
"msg": ""
}
5. POST /pre-transaction/broadcast-transaction
| Param | Type | Required | Description |
|---|
| String | Yes | Fully signed transaction (hex for EVM, base58 for Solana) |
| String | Yes | Chain ID |
| String | Yes | Sender wallet address |
| String | No | JSON string of extra options (must before sending) |
| Field | Type | Description |
|---|
| Boolean | Enable MEV protection (ETH/BSC/SOL/BASE) |
| String | Jito signed transaction (Solana) |
Response:
| Field | Type | Description |
|---|
| String | OKX order tracking ID |
| String | On-chain transaction hash |
json
{
"code": "0",
"data": [{ "orderId": "123456789", "txHash": "0xabc...def" }],
"msg": ""
}
6. GET /post-transaction/orders
| Param | Type | Required | Description |
|---|
| String | Yes | Wallet address |
| String | Yes | Chain ID |
| String | No | Specific order ID (from broadcast response) |
| String | No | Filter by status: =Pending, =Success, =Failed |
| String | No | Pagination cursor |
| String | No | Max results per page (default 20) |
Response:
| Field | Type | Description |
|---|
| String | Pagination cursor for next page |
| Array | Order list (nested under each data element) |
| String | Order ID |
| String | On-chain transaction hash |
data[].orders[].chainIndex
| String | Chain ID |
| String | Sender address |
| String | Order status: =Pending, =Success, =Failed |
data[].orders[].failReason
| String | Failure reason (if failed) |
json
{
"code": "0",
"data": [{
"cursor": "1",
"orders": [{
"orderId": "123456789",
"txHash": "0xabc...def",
"chainIndex": "1",
"address": "0x...",
"txStatus": "2",
"failReason": ""
}]
}],
"msg": ""
}
Input / Output Examples
User says: "What's the current gas price on Ethereum?"
GET /api/v6/dex/pre-transaction/gas-price?chainIndex=1
-> Display:
Base fee: 18 Gwei
Max fee: 25 Gwei
Priority fee: 2 Gwei
User says: "Simulate this swap transaction before I send it"
POST /api/v6/dex/pre-transaction/simulate
Body: {
"chainIndex": "1",
"fromAddress": "0xYourWallet",
"toAddress": "0xDexContract",
"txAmount": "1000000000000000000",
"extJson": { "inputData": "0x..." }
}
-> Display:
Simulation: SUCCESS (failReason is empty)
Estimated gas: 145,000
Intent: Token Swap
User says: "Broadcast my signed transaction"
POST /api/v6/dex/pre-transaction/broadcast-transaction
Body: {
"signedTx": "0xf86c...signed",
"chainIndex": "1",
"address": "0xYourWallet"
}
-> Display:
Broadcast successful!
Order ID: 123456789
Tx Hash: 0xabc...def
User says: "Check the status of my broadcast order"
GET /api/v6/dex/post-transaction/orders?address=0xYourWallet&chainIndex=1&orderId=123456789
-> Response: data[0].orders[0] contains order details
-> Display:
Order 123456789: Success (txStatus=2)
Tx Hash: 0xabc...def
Confirmed on-chain
Edge Cases
- MEV protection: Broadcasting through OKX nodes may offer MEV protection on supported chains — confirm with OKX documentation for chain-specific behavior.
- Solana special handling: Solana signed transactions use base58 encoding (not hex). Ensure the format matches the chain.
- Chain not supported (81104): call
/pre-transaction/supported/chain
first to verify. Not all chains support all endpoints.
- Node return failed (81451): the underlying blockchain node rejected the transaction. Common causes: insufficient gas, nonce too low, contract revert. Retry with corrected parameters.
- Wallet type mismatch (81108): the address format does not match the chain (e.g., EVM address on Solana chain).
- 429 rate limit: exponential backoff with jitter. See Rate Limit & Fee Docs for tier-specific RPS limits (Trial: 1 RPS, Start-up: 2-50 RPS, Enterprise: custom).
- Cross-skill pipeline rate limit: when chaining calls across multiple skills (e.g., swap → simulate → broadcast), add 300-500ms delay between requests to avoid triggering rate limit (error code ).
- Network error: retry once, then prompt user to try again later
- Request timeout: all API calls must set a 10-second timeout limit
- Transaction already broadcast: if the same is broadcast twice, the API may return an error or the same — handle idempotently.
Amount Display Rules
- Gas prices in Gwei for EVM chains (), never raw wei
- Gas limit as integer (, )
- USD gas cost estimate when possible
- Transaction values in UI units (), never base units
Global Notes
- This skill does NOT sign transactions — it only broadcasts pre-signed transactions
- Amounts in API params use minimal units (wei/lamports)
- Gas price fields: use
eip1559Protocol.suggestBaseFee
+ eip1559Protocol.proposePriorityFee
for EIP-1559 chains, for legacy
- EVM contract addresses must be all lowercase
- For swap quote and execution → use
- For market prices → use
- For balance queries → use
- For token search → use
- For transaction broadcasting → use this skill ()