LeoKit provides comprehensive error tracking through trace IDs. Every API error includes a trace_id that you can use to retrieve detailed debugging information, including the full request context, error details, and timestamps.
How Trace IDs Work
When an API request fails, the error response includes a trace_id:
{
"error": "Insufficient balance (including gas fees).",
"status": 400,
"code": "INSUFFICIENT_BALANCE",
"trace_id": "tr_abc123xyz456",
"context": {
"required": "1.05 ETH",
"available": "1.00 ETH"
}
}
You can use this trace_id to retrieve full error details from the tracking endpoint.
Retrieving Error Details
Endpoint
GET /leokit/trace/[traceId]
Example Request
curl -X GET 'https://api.leodex.io/leokit/trace/tr_abc123xyz456' \
-H 'Api-Key: your_api_key_here'
Response
{
"trace_id": "tr_abc123xyz456",
"client_api": "client_key_here",
"error_details": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance (including gas fees).",
"status": 400,
"context": {
"required": "1.05 ETH",
"available": "1.00 ETH",
"gas_estimate": "0.05 ETH"
}
},
"timestamp": "2026-01-15T12:34:56.789Z",
"endpoint": "/leokit/deposit",
"request_params": {
"quote_id": "01936b4a-7c8e-7890-abcd-ef1234567890",
"selected_protocol": "thorchain"
}
}
Response Fields
| Field | Description |
|---|
trace_id | Unique identifier for this error |
client_api | Your API key (for verification) |
error_details.code | Error code (e.g., INSUFFICIENT_BALANCE) |
error_details.message | Human-readable error message |
error_details.status | HTTP status code |
error_details.context | Additional context (varies by error) |
timestamp | When the error occurred (ISO 8601) |
endpoint | Which API endpoint failed |
request_params | Parameters that were sent |
Common Use Cases
1. Debugging Failed Deposits
async function debugFailedDeposit(traceId) {
const trace = await fetch(
`https://api.leodex.io/leokit/trace/${traceId}`,
{ headers: { "Api-Key": "your_api_key_here" } }
).then(r => r.json());
console.log("Failed endpoint:", trace.endpoint);
console.log("Quote ID:", trace.request_params.quote_id);
console.log("Protocol:", trace.request_params.selected_protocol);
console.log("Error:", trace.error_details.message);
// Check specific error types
if (trace.error_details.code === "INSUFFICIENT_BALANCE") {
console.log("User needs:", trace.error_details.context.required);
console.log("User has:", trace.error_details.context.available);
}
}
2. Error Pattern Analysis
Track error frequencies to identify systemic issues:
async function analyzeErrorPatterns(traceIds) {
const traces = await Promise.all(
traceIds.map(id =>
fetch(`https://api.leodex.io/leokit/trace/${id}`, {
headers: { "Api-Key": "your_api_key_here" }
}).then(r => r.json())
)
);
// Group by error code
const errorCounts = traces.reduce((acc, trace) => {
const code = trace.error_details.code;
acc[code] = (acc[code] || 0) + 1;
return acc;
}, {});
console.log("Error distribution:", errorCounts);
// Output: { INSUFFICIENT_BALANCE: 5, QUOTE_EXPIRED: 2, ... }
}
3. Customer Support Integration
Display error details to support agents:
function SupportTicket({ traceId }) {
const [trace, setTrace] = useState(null);
useEffect(() => {
fetch(`https://api.leodex.io/leokit/trace/${traceId}`, {
headers: { "Api-Key": "your_api_key_here" }
})
.then(r => r.json())
.then(setTrace);
}, [traceId]);
if (!trace) return <p>Loading error details...</p>;
return (
<div className="support-ticket">
<h2>Error Report</h2>
<dl>
<dt>Time:</dt>
<dd>{new Date(trace.timestamp).toLocaleString()}</dd>
<dt>Error Code:</dt>
<dd>{trace.error_details.code}</dd>
<dt>Message:</dt>
<dd>{trace.error_details.message}</dd>
<dt>Endpoint:</dt>
<dd>{trace.endpoint}</dd>
<dt>Request Parameters:</dt>
<dd><pre>{JSON.stringify(trace.request_params, null, 2)}</pre></dd>
</dl>
</div>
);
}
4. Automated Monitoring
Set up alerts for critical errors:
async function monitorErrors(traceIds) {
const criticalErrors = [
'INTERNAL_SERVER_ERROR',
'PROTOCOL_TIMEOUT',
'BLOCKCHAIN_SYNC_ERROR'
];
for (const traceId of traceIds) {
const trace = await fetch(
`https://api.leodex.io/leokit/trace/${traceId}`,
{ headers: { "Api-Key": "your_api_key_here" } }
).then(r => r.json());
if (criticalErrors.includes(trace.error_details.code)) {
// Send alert to monitoring system
await sendAlert({
severity: 'critical',
message: trace.error_details.message,
traceId: trace.trace_id,
timestamp: trace.timestamp
});
}
}
}
Error Categories
Errors are grouped into categories for easier debugging:
Validation Errors (HTTP 400)
Client-side issues like invalid parameters or malformed requests.
Common Codes:
BAD_REQUEST - Malformed JSON or invalid types
WRONG_PROTOCOL - Unsupported protocol selected
INVALID_TOLERANCE_BPS - Slippage tolerance out of range
Debugging:
if (trace.error_details.status === 400) {
console.log("Fix client-side validation:");
console.log("- Check parameter types");
console.log("- Verify required fields");
console.log("- Validate addresses");
}
Balance & Amount Errors (HTTP 400)
Insufficient funds or amounts outside valid ranges.
Common Codes:
INSUFFICIENT_BALANCE - Not enough tokens/gas
NOT_ENOUGH_GAS - Can’t pay transaction fees
UNDER_DUST_LIMIT - Output amount too small
Debugging:
if (trace.error_details.code === 'INSUFFICIENT_BALANCE') {
const { required, available } = trace.error_details.context;
console.log(`User needs ${required} but has ${available}`);
console.log("Suggest: Reduce swap amount or add funds");
}
Quote & Transaction Errors (HTTP 400/404)
Issues with quotes or transaction generation.
Common Codes:
QUOTE_EXPIRED - Quote older than 15 minutes
QUOTE_NOT_FOUND - Invalid quote_id
NO_ROUTES_AVAILABLE - No protocols support this swap
Debugging:
if (trace.error_details.code === 'QUOTE_EXPIRED') {
console.log("Quote expired at:", trace.timestamp);
console.log("Suggest: Request a new quote");
}
Server & Protocol Errors (HTTP 500/503)
Backend or protocol integration issues.
Common Codes:
INTERNAL_SERVER_ERROR - Unexpected server error
PROTOCOL_TIMEOUT - Protocol didn’t respond in time
BLOCKCHAIN_SYNC_ERROR - Node syncing issue
Debugging:
if (trace.error_details.status >= 500) {
console.log("Server-side issue - retry may help");
console.log("If persists, contact support with trace_id:", trace.trace_id);
}
Retention Policy
Error logs are retained for 30 days. Download critical traces within this window.
After 30 days, the trace endpoint will return:
{
"error": "Trace not found or expired",
"status": 404,
"code": "TRACE_NOT_FOUND"
}
Best Practices
Always save trace_id - Store it in your database alongside transaction records for later debugging.
Show trace_id to users - Include it in error messages so users can reference it in support tickets.
Implement retry logic - For transient errors like PROTOCOL_TIMEOUT, automatically retry with exponential backoff.
Log error patterns - Track which errors occur most frequently to improve your integration.
Use context fields - The context object contains actionable debugging information specific to each error type.
Error Response Handling
Build a robust error handler that uses trace IDs:
async function handleApiError(error) {
if (!error.trace_id) {
console.error("No trace_id available");
return;
}
// Fetch full error details
const trace = await fetch(
`https://api.leodex.io/leokit/trace/${error.trace_id}`,
{ headers: { "Api-Key": "your_api_key_here" } }
).then(r => r.json());
// Log to monitoring service
await logToMonitoring({
traceId: trace.trace_id,
errorCode: trace.error_details.code,
endpoint: trace.endpoint,
timestamp: trace.timestamp
});
// Show user-friendly message
const userMessage = getUserFriendlyMessage(trace.error_details.code);
showNotification({
type: 'error',
message: userMessage,
traceId: trace.trace_id
});
// Decide if we should retry
if (isRetryableError(trace.error_details.code)) {
await retryWithBackoff(trace.endpoint, trace.request_params);
}
}
function isRetryableError(code) {
return [
'PROTOCOL_TIMEOUT',
'INTERNAL_SERVER_ERROR',
'SERVICE_UNAVAILABLE'
].includes(code);
}
Next Steps