Telemetry Usage API
This is the main API you’ll use to ship your AI usage data to Antarctica. By sending us the specifics of each LLM call, we can compute your analytics and show you exactly what’s happening across your infrastructure.
POST https://otm-api.antarctica.io/v1/telemetry/usage
The Payload Schema
We use a strict schema to make sure your analytics stay clean. If a request doesn’t match the types below, you’ll get a 400 Validation Error.
1. Request Info (request) : Object, Required
| Field | Type | Required? | Description |
|---|---|---|---|
modelId | string | Yes | The specific model used. e.g., "gpt-4o" or "claude-3-5-sonnet". |
status | string | Yes | Did the call work? Use "success" or "error". |
provider | string | Yes | Who provided the model? e.g., "openai", "anthropic", or "google". |
2. User Info (user) : Object, Required
| Field | Type | Required? | Description |
|---|---|---|---|
id | string | Yes | A unique ID for the user making the request (e.g., a hashed email or UUID). |
type | string | Yes | Is this an "external" customer or an "internal" employee? |
name | string | No | Optional: The display name of the user. |
3. Tokens (tokens) : Object, Required on Success
Finding These Values: Unsure where to find these in your LLM’s response? Check out our Extracting Metrics guide for OpenAI, Gemini, and Claude examples.
| Field | Type | Required? | Description |
|---|---|---|---|
input | uint | Yes | The number of tokens you sent to the model (prompt). |
output | uint | Yes | The number of tokens the model sent back (completion). |
total | uint | No | The combined total of input and output tokens. |
4. Timing Object (timing) : Object, Conditionally Required
Note: Required if the
request.statusevaluates to"success".
| Field | Type | Required? | Description |
|---|---|---|---|
startTime | ISO 8601 | Yes | Exactly when you started the API request. |
firstTokenTime | ISO 8601 | Yes | When you received the very first chunk of data (TTFT). |
lastTokenTime | ISO 8601 | Yes | When the full response was finished. |
latencyMs | uint | No | Total duration in milliseconds (we can calculate this if you leave it blank). |
5. Extra Details
errorobject (Required if status is “error”): Include acodeandmessage.ioobject (Optional): If you want to log the actualpromptandresponsetext. Only use this if your privacy policy allows it!contextobject (Optional): A place for any extra tags you want to track, like{"projectId": "my_app_v1"}.
The Response Schema
The API will return an HTTP 202 Accepted status when your telemetry package is successfully validated and queued for ingestion.
Success Response (202 Accepted)
| Field | Type | Description |
|---|---|---|
requestId | string | The unique ID assigned to this ingestion event. |
status | string | Always returns "accepted" for successful requests. |
message | string | A human-readable confirmation message. |
timestamp | string | The ISO 8601 timestamp of when the data was recorded. |
usage | object | An object containing the processed token counts for the record. |
JSON Payload Examples
Sometimes it is easiest to just see the raw data. Below are complete, formatted JSON payloads you can use as templates for your system.
1. Successful Inference
When your LLM generates a successful response, send the complete tokens and timing metrics:
{
"request": {
"modelId": "gpt-4-turbo",
"status": "success",
"provider": "openai"
},
"user": {
"id": "usr_9a8b7c6d",
"type": "external",
"name": "Jane Doe"
},
"tokens": {
"input": 145,
"output": 810,
"total": 955
},
"timing": {
"startTime": "2024-05-18T14:30:00.000Z",
"firstTokenTime": "2024-05-18T14:30:01.200Z",
"lastTokenTime": "2024-05-18T14:30:05.400Z",
"latencyMs": 5400
},
"io": {
"prompt": "Write a python script to reverse a string.",
"response": "Here is your python script..."
},
"context": {
"projectId": "prj_python_tutor",
"location": "us-east-1"
}
}Expected Success Response (202 Accepted)
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted",
"usage": {
"inputTokens": 145,
"outputTokens": 810,
"totalTokens": 955
},
"message": "Usage recorded successfully.",
"timestamp": "2024-05-18T14:30:06.124Z"
}2. Failed Inference (System Error)
If the prompt was flagged, or the provider API timed out, you do not send tokens or timing. Instead, pass the error details:
{
"request": {
"modelId": "claude-3-opus",
"status": "error",
"provider": "anthropic"
},
"user": {
"id": "usr_1x2y3z",
"type": "internal"
},
"error": {
"code": "provider_timeout",
"message": "Anthropic API failed to respond within 30 seconds.",
"stack": "Error: timeout at Object.request..."
},
"context": {
"projectId": "internal_testing"
}
}Implementation Examples
Here is how you might implement this in your actual code. We recommend sending these requests in the background so you don’t slow down your users.
import crypto from "crypto";
/**
* Dispatch Telemetry cleanly and asynchronously without blocking the main event loops.
*/
async function dispatchTelemetryAnalytics(completionMetrics) {
const payload = {
request: {
modelId: "gpt-4-turbo",
status: "success",
provider: "openai",
},
user: { id: "user_a1b2c3", type: "external" },
tokens: {
input: completionMetrics.prompt_tokens,
output: completionMetrics.completion_tokens,
},
timing: {
startTime: completionMetrics.time.start,
firstTokenTime: completionMetrics.time.ttft,
lastTokenTime: completionMetrics.time.end,
},
context: {
projectId: "internal_marketing_gen",
location: "us-east-1",
},
};
try {
// Run un-awaited to execute purely in background/edge runtime
fetch("https://otm-api.antarctica.io/v1/telemetry/usage", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ANTARCTICA_SK_PROD}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(), // Crucial for enterprise reliability
},
body: JSON.stringify(payload),
// Set an aggressive timeout to ensure thread release
signal: AbortSignal.timeout(3000),
}).catch((err) =>
console.warn("[Analytics Warning] Dropped package:", err),
);
} catch (err) {
// Ensures your primary application completely ignores reporting crashes
console.error("Critical parsing error during telemetry generation", err);
}
}