---
url: https://simpledatalogs.com/docs/api/telemetry.md
description: >-
  Send requests, jobs, scheduled tasks and commands with their queries, outgoing
  calls and exceptions as telemetry objects on the same ingest endpoint.
---

# Telemetry objects

Telemetry rides the same endpoint as events: `POST /v1/ingest`, NDJSON, one object per line, the same keys and responses.
An object with `kind` set to `request`, `job`, `task`, `command`, `exception` or `span` is telemetry; anything else is an event or a log line.

The [Laravel SDK](/sdks/laravel#telemetry) sends all of this for you. Use this page to write your own sender.

## A bundle

One object per request, job run, scheduled task run or command: the root, its children, a summary and its exceptions.

```json
{"kind":"request","event_id":"0192f0c4-7b1e-7cc1-9a51-3f1c2d4e5a6b","ts":"2026-10-20T09:14:03.410Z",
 "trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7",
 "name":"GET /orders/{order}","duration_ms":182.4,"status":"ok","http_status":200,"method":"GET",
 "user_id":"42","release":"2026.10.3",
 "spans":[
   {"kind":"query","span_id":"a1b2c3d4e5f60718","start_ms":20.0,"duration_ms":61.0,"name":"select * from order_lines where order_id = ?","count":37},
   {"kind":"http","span_id":"b2c3d4e5f6071829","start_ms":90.3,"duration_ms":40.1,"name":"POST api.stripe.com","http_status":200}],
 "summary":{"queries":{"count":38,"duration_ms":66.9}},
 "exceptions":[{"type":"App\\Exceptions\\PaymentDeclined","message":"Card declined","handled":true,
   "frames":[{"file":"app/Services/Payments.php","line":88,"function":"charge","in_app":true}]}]}
```

| Field | Root (`request` `job` `task` `command`) | Child (`query` `http` `cache` `mail` `notification` `span`) |
|---|---|---|
| `event_id`, `ts` | Required; `ts` is the start | — |
| `trace_id` | Required, 32 hex | Inherited |
| `span_id` | Required, 16 hex | 16 hex |
| `parent_span_id` | Optional; set it on a job dispatched by a request so both show in one trace | Optional, else the root |
| `name` | Route pattern, job class, task command or command name | SQL with `?` for values, `METHOD host`, `hit`/`miss`, a class name or free text |
| `duration_ms` | Required | Optional |
| `start_ms` | — | Offset from the root's `ts` |
| `status` | `ok` or `error` (a 5xx counts as `error`) | Same |
| `http_status`, `method`, `route` | Requests | `http_status` on `http` children |
| `count`, `max_ms` | — | Identical calls folded into one, and the slowest |
| `summary` | Exact totals per kind, kept even when you send no children | — |
| `exceptions` | Up to 5 | — |
| `user_id`, `release`, `props` | Optional | `props` optional |

### Limits

* 64 KB per object as JSON; a bigger one is kept in Unparsed as `bundle_too_large`, never stored in part.
* 60 children after folding identical ones; the slowest are kept and the rest add up as one `(other)` child per kind.
* 5 exceptions, 50 frames and 8 KB per stack, 100 props.
* Names up to 512 bytes, SQL up to 2 KB.
* Up to 1,000 distinct names per kind per day; later new names count under `(other)`.

### What we clean up

* Route names with ids in them (`/orders/8812`) become patterns (`/orders/{id}`); query strings are dropped.
* SQL literals become `?`. Send the SQL your framework already shows with placeholders; never send bound values.
* `http` names keep `METHOD host` only.

## Exceptions

Inside a bundle, or on their own with `kind: exception`:

```json
{"kind":"exception","event_id":"0192f0c4-8a2b-7cc1-9a51-3f1c2d4e5a6c","ts":"2026-10-20T09:15:00Z",
 "type":"NSRangeException","message":"index 7 beyond bounds [0 .. 4]","handled":false,
 "frames":[{"file":"Feed/FeedViewModel.swift","line":120,"function":"apply(update:)","in_app":true}],
 "release":"3.2.0 (411)"}
```

* They are stored as events named `exception` (level `error`, or `critical` when `handled` is false), so Logs, boards and alerts see them.
* They group into **issues** by type, the message with numbers, ids and quoted text masked, and the first in-app frame. Send your own `fingerprint` to group differently.

## Logs in a trace

Add `trace_id` (32 hex) and `span_id` (16 hex) to any log line or event. The Logs page links it to the trace.

## What counts toward your plan

A bundle counts one event per started 4 KB of JSON, or one per exception inside it if that is more: a typical request, with or without its queries, is **one event**. A standalone span counts one event per started 4 KB; a standalone exception counts one.
