Telemetry
Browse docs

Use this doc with your coding agent

Open a focused prompt pack for Claude Code, Codex, Cursor, or another coding agent, then adapt it to the workflow covered here.

On this page
  1. Configure the key
  2. Send one event
  3. Send a compatible batch
  4. Run SQL
  5. Export a larger result
  6. Inspect and verify the table
  7. Retry and exit-code policy

cURL and HTTP API Examples

Use cURL to verify an API key, reproduce an SDK request, automate a server-side script, or test failure handling before adding instrumentation to an application.

Configure the key

Export the key in a shell that does not record secret values:

export TELEMETRY_API_KEY="YOUR_API_KEY"

Use a write-scoped key for ingestion and a separate read-scoped key for queries or reports. Disable shell tracing around commands that expand the key.

Send one event

curl --fail-with-body \
  --connect-timeout 2 \
  --max-time 10 \
  --request POST \
  "https://api.telemetry.sh/log" \
  --header "Authorization: ${TELEMETRY_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "table": "api_request_completed",
  "data": {
    "event_id": "evt_request_101",
    "route_template": "/api/projects/:id",
    "method": "GET",
    "status_code": 200,
    "status": "success",
    "latency_ms": 184
  }
}
JSON

Telemetry adds timestamp_utc. Do not send API keys, authorization headers, cookies, raw request bodies, prompts, or private customer content as event fields.

Send a compatible batch

The data field can be an array:

curl --fail-with-body \
  --connect-timeout 2 \
  --max-time 10 \
  --request POST \
  "https://api.telemetry.sh/log" \
  --header "Authorization: ${TELEMETRY_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "table": "job_completed",
  "data": [
    {
      "event_id": "evt_job_101",
      "job_name": "invoice_sync",
      "status": "success",
      "duration_ms": 912
    },
    {
      "event_id": "evt_job_102",
      "job_name": "invoice_sync",
      "status": "failed",
      "duration_ms": 2401,
      "error_type": "provider_timeout"
    }
  ]
}
JSON

Keep every object compatible with the same table schema. A batch reduces request overhead but increases the number of events affected by one failed request.

Run SQL

curl --fail-with-body \
  --connect-timeout 2 \
  --max-time 30 \
  --request POST \
  "https://api.telemetry.sh/query" \
  --header "Authorization: ${TELEMETRY_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "query": "SELECT route_template, COUNT(*) AS requests, ROUND(AVG(latency_ms), 0) AS avg_latency_ms FROM api_request_completed WHERE timestamp_utc >= now() - INTERVAL '24 hours' GROUP BY route_template ORDER BY requests DESC;"
}
JSON

Check the status, data, and key_order fields instead of assuming a non-empty result.

Export a larger result

Start an asynchronous Parquet export:

curl --fail-with-body \
  --connect-timeout 2 \
  --max-time 30 \
  --request POST \
  "https://api.telemetry.sh/query/async" \
  --header "Authorization: ${TELEMETRY_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "query": "SELECT * FROM api_request_completed WHERE timestamp_utc >= now() - INTERVAL '30 days' ORDER BY timestamp_utc DESC;",
  "format": "parquet"
}
JSON

Poll the returned status_url with the same authorization header. When query_status is completed, download the download_url. Stop polling on failed and enforce an overall deadline.

Inspect and verify the table

curl --fail-with-body \
  --connect-timeout 2 \
  --max-time 10 \
  "https://api.telemetry.sh/tables/api_request_completed/schema" \
  --header "Authorization: ${TELEMETRY_API_KEY}"

Send synthetic success, failure, retry, and timeout cases. Confirm field types, units, UTC timestamps, and the absence of sensitive fields before creating a dashboard or alert.

Retry and exit-code policy

--fail-with-body exits nonzero for HTTP failures while preserving the response body for safe diagnostics.

  • Exit 6: DNS resolution failed.
  • Exit 7: connection failed.
  • Exit 28: timeout; the server may or may not have accepted the request.
  • HTTP 400: fix the request; do not retry unchanged.
  • HTTP 401 or 403: replace the credential or correct its scope.
  • HTTP 429, 502, 503, or 504: retry with bounded exponential backoff and jitter.

Reuse the same event_id for a logical event. Do not use --retry-all-errors without accounting for duplicate delivery.

See the Log API, Query API, Tables API, and event delivery guide.

Related product capability

Capture stable event names, typed fields, and privacy-reviewed context.

Ownership and technical references

The Telemetry editorial team owns this explanation; the product team reviews behavior, examples, and boundaries.

Review the editorial standard