Skip to main content
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

FieldDescription
trace_idUnique identifier for this error
client_apiYour API key (for verification)
error_details.codeError code (e.g., INSUFFICIENT_BALANCE)
error_details.messageHuman-readable error message
error_details.statusHTTP status code
error_details.contextAdditional context (varies by error)
timestampWhen the error occurred (ISO 8601)
endpointWhich API endpoint failed
request_paramsParameters 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