Skip to main content
When your chatbot conversation or agent run is in flight, every action becomes an event.
Bundled together they form a trace – a structured replay of what happened, step‑by‑step.
EventWhen to use
traceThe root container for a whole conversation / agent run.
llmStart and end of every LLM call.
toolCalls to a function / external tool invoked by the model.
retrieverRAG queries and the chunks they return.
logAnything else worth seeing while debugging (system prompts, branches, errors…).
The full schema lives in API ▸ Ingestion.

Understanding testId and traceId

Two IDs appear on trace events — here’s what each one does:
FieldWho sets itWhen to include
testIdAvido (via webhook)Only when the trace originates from an Avido test. Pass the testId from the webhook payload. Do not set it for traces that come from real user interactions.
traceIdYou (optional)Setting traceId client-side is optional — the server generates one automatically if you don’t. If you do set it, use a random UUID and keep the same value across all steps in the trace.
Do not set traceId equal to testId. They serve different purposes: testId links the trace to an Avido test run for evaluation, while traceId groups events together into a single trace.

  1. Collect events in memory as they happen.
  2. Flush once at the end (or on fatal error).
  3. Add a log event describing the error if things blow up.
  4. Keep tracing async – never block your user.
  5. Evaluation‑only mode? Only ingest when the run came from an Avido test → check for testId from the Webhook.
  6. LLM events should contain the raw prompt & completion – strip provider JSON wrappers.

SDK installation

npm install @avidoai/sdk-node

Ingesting events

You can send events:
  • Directly via HTTP
  • Via our SDKs (Node: @avidoai/sdk-node, Python: avido)
When authenticating with an API key, include both the x-api-key and x-application-id headers. The application ID should match the application that owns the key so the request can be authorized.
curl --request POST \
  --url https://api.avidoai.com/v0/ingest \
  --header 'Content-Type: application/json' \
  --header 'x-application-id: <application-id>' \
  --header 'x-api-key: <api-key>' \
  --data '{
  "events": [
    {
      "type": "trace",
      "timestamp": "2025-05-15T12:34:56.123455Z",
      "referenceId": "123e4567-e89b-12d3-a456-426614174000",
      "metadata": {
        "source": "chatbot"
      }
    },
    {
      "type": "llm",
      "event": "start",
      "traceId": "123e4567-e89b-12d3-a456-426614174000",
      "timestamp": "2025-05-15T12:34:56.123456Z",
      "modelId": "gpt-4o-2024-08-06",
      "params": {
        "temperature": 1.2
      },
      "input": [
        {
          "role": "user",
          "content": "Tell me a joke."
        }
      ]
    }
  ]
}'

Tip: map your IDs

If you already track a conversation / run in your own DB, pass that same ID as referenceId.
It makes liftover between your system and Avido effortless.

Event types in depth

Every call to client.ingest.create() accepts an array of events. The first event is usually a trace (the root container), followed by one or more step events.

trace — root container

Every ingestion batch should start with a trace event. It groups all subsequent steps together.
await client.ingest.create({
  events: [
    {
      type: 'trace',
      timestamp: new Date().toISOString(),
      referenceId: 'your-internal-conversation-id', // links to your system
      testId: webhookBody.testId,                   // links to an Avido test run
      metadata: { source: 'chatbot', userId: '42' },
    },
  ],
});
FieldRequiredDescription
typeYesAlways "trace"
timestampYesISO 8601 timestamp
referenceIdNoYour own ID for this conversation / run
traceIdNoClient-provided UUID to identify this trace. Optional — the server generates one if omitted. If set, use the same random UUID for all steps in the trace.
testIdNoThe testId from a webhook payload — links the trace to an Avido test run. Only set this for test-originated traces; omit it for real user interactions.
metadataNoArbitrary key-value pairs for filtering and search

llm — LLM calls

Track every call to a language model. Use event: "start" when the call begins and event: "end" when it completes, or send a single event with both input and output after the call finishes.
await client.ingest.create({
  events: [
    {
      type: 'trace',
      timestamp: new Date().toISOString(),
    },
    {
      type: 'llm',
      event: 'start',
      timestamp: startTime.toISOString(),
      modelId: 'gpt-4o-2024-08-06',
      params: { temperature: 0.7, maxTokens: 1024 },
      input: [
        { role: 'system', content: 'You are a helpful assistant.' },
        { role: 'user', content: 'Summarize this document.' },
      ],
    },
    {
      type: 'llm',
      event: 'end',
      timestamp: endTime.toISOString(),
      output: [
        { role: 'assistant', content: 'Here is the summary...' },
      ],
      tokenUsage: { prompt: 120, completion: 85 },
    },
  ],
});
Send the raw prompt and completion values. Strip any provider-specific JSON wrappers so Avido can display and evaluate them consistently.

tool — function / tool calls

Log every tool or function call your model makes.
{
  type: 'tool',
  timestamp: new Date().toISOString(),
  toolInput: JSON.stringify({ query: 'AAPL stock price' }),
  toolOutput: JSON.stringify({ price: 187.42, currency: 'USD' }),
}

retriever — RAG queries

Track retrieval-augmented generation lookups and the chunks they return.
{
  type: 'retriever',
  timestamp: new Date().toISOString(),
  query: 'What is the refund policy?',
  result: JSON.stringify([
    { chunk: 'Refunds are available within 30 days...', score: 0.92 },
    { chunk: 'For premium plans, contact support...', score: 0.87 },
  ]),
}

log — everything else

Use log events for system prompts, branching decisions, error details, or anything else worth seeing during debugging.
{
  type: 'log',
  timestamp: new Date().toISOString(),
  body: 'User triggered fallback branch — no documents matched above threshold',
}

Full end-to-end example

A complete example capturing a realistic agent run with multiple event types:
import Avido from '@avidoai/sdk-node';

const client = new Avido({
  applicationId: process.env['AVIDO_APPLICATION_ID'],
  apiKey: process.env['AVIDO_API_KEY'],
});

async function handleRequest(prompt: string, testId?: string) {
  const events: Record<string, unknown>[] = [];
  const traceStart = new Date();

  // 1. Root trace
  events.push({
    type: 'trace',
    timestamp: traceStart.toISOString(),
    testId,
    metadata: { source: 'api' },
  });

  // 2. Retriever step
  const docs = await vectorSearch(prompt);
  events.push({
    type: 'retriever',
    timestamp: new Date().toISOString(),
    query: prompt,
    result: JSON.stringify(docs),
  });

  // 3. LLM call
  const llmStart = new Date();
  const completion = await callLLM(prompt, docs);
  events.push(
    {
      type: 'llm',
      event: 'start',
      timestamp: llmStart.toISOString(),
      modelId: 'gpt-4o-2024-08-06',
      input: [
        { role: 'system', content: 'Answer using the provided context.' },
        { role: 'user', content: prompt },
      ],
    },
    {
      type: 'llm',
      event: 'end',
      timestamp: new Date().toISOString(),
      output: [{ role: 'assistant', content: completion.text }],
      tokenUsage: {
        prompt: completion.usage.promptTokens,
        completion: completion.usage.completionTokens,
      },
    },
  );

  // 4. Flush everything in one call
  await client.ingest.create({ events });

  return completion.text;
}

Fetching traces

Use the SDK to list or retrieve traces for debugging and analysis.
// List recent traces
const traces = await client.traces.list({ limit: 10 });

for (const trace of traces.data) {
  console.log(trace.id, trace.referenceId);
}

// Retrieve a specific trace by ID
const trace = await client.traces.retrieve('trace-uuid-here');
console.log(trace.data);

Error handling

Wrap your ingestion calls so a tracing failure never crashes your application.
try {
  await client.ingest.create({ events });
} catch (err) {
  // Log but don't crash — tracing is secondary to your user's request
  console.error('Avido ingestion failed:', err);
}

Next steps