diff --git a/docs/evals/experiments.mdx b/docs/evals/experiments.mdx index 685f45a..2f21565 100644 --- a/docs/evals/experiments.mdx +++ b/docs/evals/experiments.mdx @@ -1,7 +1,7 @@ --- title: Experiments description: Run a prompt version or your own code on each item of a dataset, score the outputs, and compare them with the baseline in the dashboard or in CI. -lastModified: 2026-10-30 +lastModified: 2026-10-31 --- An experiment runs a prompt version or your code on each item of a [dataset](/evals/datasets), then scores each output with [evaluators](/evals/evaluators). The experiment page compares the scores with the baseline of the dataset, so you can see which items became better or worse. @@ -212,7 +212,7 @@ jobs: with: node-version: 24 - run: npm ci - - uses: telemetry-dev/telemetry/actions/experiment@main + - uses: telemetry-dev/telemetry/actions/experiment@experiment-action-v1 with: dataset: support-golden script: evals/reply.eval.ts @@ -235,7 +235,7 @@ The action sets `TELEMETRY_DEV_ENVIRONMENT` to `experiment` if the job does not The comment shows the status of each experiment and the count of items that ran. Its table of scores has the **Value**, the **Change**, and the **Pass mark** of each score. The action writes one comment for each workflow, job, and input, and changes that comment on each later push. -To keep a workflow the same when `main` changes, use a commit SHA of `telemetry-dev/telemetry` in place of `@main`. +The tag `experiment-action-v1` moves to each 1.x release of the action, and a change that can break a workflow gets a new major tag. To keep a workflow the same, use the tag of one release, such as `experiment-action-v1.0.0`, or its commit SHA. The [releases](https://github.com/telemetry-dev/telemetry/releases) of `telemetry-dev/telemetry` list the changes. ## Stop, run again, or delete an experiment diff --git a/docs/platform/analytics.mdx b/docs/platform/analytics.mdx index f0ff071..11cd7cd 100644 --- a/docs/platform/analytics.mdx +++ b/docs/platform/analytics.mdx @@ -1,7 +1,7 @@ --- title: Analytics description: Track a project's request volume, latency, errors, tokens, and cost over time. -lastModified: 2026-10-26 +lastModified: 2026-10-31 --- The **Overview** page shows how a project is doing over a period: how many requests it served, how fast, how many failed, and what the model calls cost. It combines trace data with the OTLP metrics that your SDKs report. @@ -27,7 +27,7 @@ Each card shows a total for the period and a chart of the value over the period: | **LLM tokens** | Input tokens plus output tokens | | **Active users** | Number of distinct user IDs in the traces | -The charts use hourly points for the 7-day period and daily points for longer periods. Select a card to open **Traces**; the **Error rate** card shows only traces with errors. +The charts use hourly points for the 7-day period and daily points for longer periods. Select a card to open **Traces** for the same period; the **Error rate** card shows only traces with errors. Each card except **Active users** compares the period with the period of the same length just before it. For **Error rate**, **p95 latency**, **LLM cost**, and **LLM tokens**, a decrease counts as an improvement. @@ -37,7 +37,7 @@ A comparison appears only if the project's retention covers both periods. For ex The **Breakdown** table groups traces by **Model** at first. Select **Provider**, **User**, or **Operation** to change the grouping. Each row shows the group's **Requests**, **Error rate**, **p95**, **Tokens**, and **Cost**. -The table shows up to 6 groups, the ones with the most requests first. Select a row to list its traces, or its spans for a model, provider, or operation. +The table shows up to 6 groups, the ones with the most requests first. Select a row to list its traces, or its spans for a model, provider, or operation. The list opens with the period of the Overview. The rows of models and providers count only model calls, so their lists show only model calls too, with the **Operation: model calls** chip. Read [Find a trace or span](/platform/traces#find-a-trace-or-span). ## Read metric series diff --git a/docs/platform/mcp-server.mdx b/docs/platform/mcp-server.mdx index 9c47c35..e61d363 100644 --- a/docs/platform/mcp-server.mdx +++ b/docs/platform/mcp-server.mdx @@ -1,7 +1,7 @@ --- title: Connect an AI agent description: Let Claude, ChatGPT, Cursor, VS Code, or another MCP client read traces, logs, and usage from one workspace. -lastModified: 2026-10-30 +lastModified: 2026-10-31 --- telemetry.dev runs an MCP server at `https://telemetry.dev/mcp`. An AI agent connected to it can find traces, read a trace's spans and errors, list logs, and summarize token usage and cost, so you can ask questions such as "why did the last checkout run fail?" in your editor or chat app. @@ -63,7 +63,7 @@ If the page says **telemetry.dev has not verified this app**, the app's name was | `list_projects` | The workspace's projects. Every other tool needs a project from this list. | | `search_sessions` | Sessions with traces in a time window, newest first, with trace count, errors, tokens, and cost. | | `search_traces` | Traces in a time window, newest first, filtered by name, status, environment, framework, service, session, or end user, or by the model, provider, operation, agent, or tool of one of their spans. The tool filter matches a tool call by its recorded tool name, or by the span name when there is none. | -| `get_trace` | One trace's spans with models, tools, timing, tokens, cost, and error text, and its logs, in pages. It also returns `trace.url`, the trace's page in the dashboard, so an agent can give you a link to the run. | +| `get_trace` | One trace's spans with models, tools, timing, tokens, cost, and error text, and its logs, in pages. Next to its `cost_usd`, each span has `input_cost_usd`, `cache_read_cost_usd`, `cache_write_cost_usd`, `reasoning_cost_usd`, and `output_cost_usd`, which add up to it; they are null for a span without this split, such as one whose cost the SDK reported. Read [Cost by token class](/reference/cost#cost-by-token-class). It also returns `trace.url`, the trace's page in the dashboard, so an agent can give you a link to the run. | | `get_span_payload` | The captured input, output, or error of one span, in pages. Needs the extra permission below. | | `list_logs` | Log records in a time window, newest first, filtered by level, with counts per level for the whole window. | | `get_usage_summary` | Requests, errors, latency, tokens, cost, and active users for 7, 30, or 90 days, compared with the period before, broken down by model, provider, end user, or operation. The breakdown lists the top 6 groups by requests. | @@ -92,6 +92,18 @@ While a result's `next_cursor` is not null, pass it as `cursor` to get the next `search_sessions` lists sessions by the start of their latest trace in the window. A trace that started before the window ended but reached telemetry.dev after the first page was read can move its session to a page already read, so a session can be missed or listed twice. `list_logs` counts levels over the whole window on every page, so a late log can change the counts between pages. +### Errors + +Each tool that takes arguments refuses one that it does not know, so a misspelled filter returns an error instead of results without that filter. + +A tool error has a text that the agent reads and, for a client that acts on it, a code in `_meta`: + +```json +"_meta": { "dev.telemetry/error": { "code": "invalid_cursor", "retryable": false } } +``` + +The codes are `invalid_cursor`, `payloads_not_allowed`, `access_denied`, `project_not_found`, `trace_not_found`, `span_not_found`, `not_found`, `invalid_arguments`, `plan_limit`, and `server_error`. Only `server_error` is retryable. An argument that fails the tool's input schema returns an error without a code, so treat a missing code as unknown. + ### Usage reads that fail `get_usage_summary` still answers when one of its reads fails. `data_incomplete` is `true` when any read failed, such as the read of the period before. `current_unavailable` is `true` when the totals of the range were not read, and `breakdown_unavailable` is `true` when the breakdown was not read. In those cases the zeros in `current`, or the empty `breakdown`, are not data, so read them as unknown rather than as no usage. diff --git a/docs/platform/projects.mdx b/docs/platform/projects.mdx index de2a8aa..8e01ca5 100644 --- a/docs/platform/projects.mdx +++ b/docs/platform/projects.mdx @@ -1,7 +1,7 @@ --- title: Projects description: Create a project, connect an application to it, and rename or delete it. -lastModified: 2026-10-26 +lastModified: 2026-10-31 seo: description: "Use projects to keep telemetry, API keys, environments, and privacy settings separate. Create, set up, rename, or delete a project in telemetry.dev." --- @@ -67,6 +67,19 @@ Select **Settings** in the project sidebar to open the project's **General** set Deleting a project removes the project and its API keys, so the keys stop working at once. It also deletes the project's stored telemetry. You cannot undo it. +## Stop accepting telemetry + +A workspace owner or admin can stop a project from taking new data and keep what it has. Select **Settings** in the project sidebar, and turn off **Accept telemetry** under **Ingestion**. + +While it is off: + +- The project's API keys get `403 project_not_accepting_telemetry` when they send traces, logs, or metrics, start an experiment, send experiment runs, or send scores, and nothing new is stored. Read [OTLP error responses](/reference/otlp#error-responses) and [Evals API errors](/reference/evals-api#errors). +- Apps can still fetch prompts and datasets. +- The project's stored data stays. +- telemetry.dev does not score the project. Live and session evaluators, backfills, and experiment items wait, and LLM judges start no new model calls, apart from up to a minute of calls in a scoring run that began before you turned it off. An experiment stays queued or running until you turn the setting on again or stop the experiment. + +When you turn **Accept telemetry** on again, the waiting evals continue where they stopped. Live and session evaluators look back at most one hour, so if the setting was off for longer, traces that were not scored before it was turned off stay unscored. + ## Rename the workspace diff --git a/docs/platform/prompts.mdx b/docs/platform/prompts.mdx index 0f72ff9..871391d 100644 --- a/docs/platform/prompts.mdx +++ b/docs/platform/prompts.mdx @@ -1,7 +1,7 @@ --- title: Prompts description: Keep prompts in telemetry.dev, save versions, deploy one with a label, fetch it with getPrompt or get_prompt, and see its calls on traces. -lastModified: 2026-10-30 +lastModified: 2026-10-31 --- Prompts keeps the prompts of your app in telemetry.dev. You save each change as a version, and a label such as `production` says which version your app gets. To deploy a version, you move the label. Your code does not change. @@ -45,6 +45,8 @@ In a chat prompt, a **Chat history** message stands for a list of messages that Only text prompts can be included. Includes can nest at most 3 levels deep, one version can include at most 50 prompts, and includes can add at most 1,000,000 characters. telemetry.dev puts in the included text when your app fetches the prompt, so a move of a label of the included prompt changes the text that your app gets. A save, a label move, or a rename that makes includes loop back or nest too deep is refused. +You can save a version with an include that gets no version, such as one that names a label that does not exist yet, and the editor warns you. A label cannot point to such a version. Apps that fetch it with `latest` or by its version number get `include_not_found` until the include gets a version. + ## Save versions Each change to the prompt is a draft until you save it. Select **Save as v**_n_, enter an optional note in **What changed**, and select **Save version**. In the same dialog you can move labels to the new version. @@ -61,6 +63,8 @@ A label points to one version of the prompt. Your app fetches the prompt by its - **latest** is not a label that you set. It always gives the newest version. - Other labels, such as `staging`, are yours to name. Open **Manage labels** in the **Versions** tab to add, move, or remove a label. +Removing a label asks first and says which apps will get an error, including old versions of other prompts that include this prompt through that label. The removal is refused while the newest version or a labeled version of another prompt includes this prompt through that label. + Until a version has the production label, apps that fetch the prompt without a label get the error `label_not_found`. ### Protected labels @@ -71,6 +75,8 @@ Until a version has the production label, apps that fetch the prompt without a l When you promote a version to production, select **Part of the calls** and enter a share from 1 to 99 percent. That share of the calls gets the new version, and the rest get the version that production had. One session keeps one version for all of its calls. Promote the new version again with **All calls** to end the rollout, or roll production back to an earlier version. +Moving the label to one version, or removing it, ends the rollout. **Manage labels**, **Promote to production**, **Roll back**, and the Save dialog show the rollout and say that the change ends it. A rollout reaches only apps that fetch this prompt. A prompt that includes it through the label gets the version that the label had before the rollout. + ## Rename, move, or delete a prompt Open the prompt menu in the row of the prompt or on the prompt page: diff --git a/docs/platform/traces.mdx b/docs/platform/traces.mdx index ad2e300..8a39811 100644 --- a/docs/platform/traces.mdx +++ b/docs/platform/traces.mdx @@ -1,7 +1,7 @@ --- title: Traces, sessions, and logs description: Find a request, inspect its spans, follow a conversation, and read related logs. -lastModified: 2026-10-30 +lastModified: 2026-10-31 --- A trace is one request through your application. Each step inside it, such as a model call, a tool call, or an agent step, is a span. Use the trace explorer to find failed or slow requests and to see what each model call received and returned. @@ -22,11 +22,11 @@ Both lists have these filters: | Status | Shows **All statuses**, `success`, or `error`. | | Environment | Lists up to 100 environment names from your telemetry. Names match regardless of case and surrounding spaces, so `production` also shows telemetry sent as `Production`. Without a selection, the lists leave out the `experiment` environment of [experiment runs](/evals/experiments). | | Framework | Lists the frameworks detected in your telemetry. | -| Date range | Shows **Last 7 days**, **Last 30 days**, or **Last 90 days**. The default is 30 days. | +| Date range | Shows **Last 7 days**, **Last 30 days**, or **Last 90 days**. The default is 30 days. Both lists take the traces that started in the range. A long trace that started before the range does not appear, and neither do its spans. | | Session | Select a value in the **Session** column. A chip shows the filter; select it to clear the filter. | | User | In the trace list, select a value in the **User** column. A chip shows the filter; select it to clear the filter. | -A row of the **Breakdown** table on the [Overview](/platform/analytics#break-traces-down-by-a-dimension) can also open the span list filtered by **Model**, **Provider**, or **Operation**, with a chip for that filter. The **Investigate** button of a [Tool errors](/platform/alerts#tool-errors) alert opens it filtered by **Tool**, which matches tool calls by tool name, or by span name when a span has no tool name. +A row of the **Breakdown** table on the [Overview](/platform/analytics#break-traces-down-by-a-dimension) can also open the span list filtered by **Model**, **Provider**, or **Operation**, with a chip for that filter and the Overview's date range. A **Model** or **Provider** row also adds the **Operation: model calls** chip, so the list shows only model calls, the spans that the row counts. The **Investigate** button of a [Tool errors](/platform/alerts#tool-errors) alert opens it filtered by **Tool**, which matches tool calls by tool name, or by span name when a span has no tool name. The filters are part of the page URL, so you can bookmark or share a filtered view. @@ -77,31 +77,36 @@ Focus the span tree, then use these keys: | `Home` or `End` | Select the first or last span | | `→` | Expand a span, or select its first child | | `←` | Collapse a span, or select its parent | +| `Enter` or `Space` | Select the focused span and open its panel | + +When you close the span panel, focus returns to the span's row, so `Enter` opens the panel again. ### Read a span Select a span to open its panel. The panel header shows the span's type and name, with **Previous span** and **Next span** buttons. Below it, the panel shows these sections when the span has data for them: - **Error**: the error message and details, for a failed span. -- **Metrics**: when the span started, its duration, and its offset from the start of the trace. Model calls also show **First token**, **Output speed**, **Cost**, and their tokens. +- **Metrics**: when the span started, its duration, its offset from the start of the trace, and its **Span ID**, with a button to copy it. Model calls also show **First token**, **Output speed**, **Cost**, and their **Tokens**, split into **Input**, **Cache write**, **Cached input**, **Reasoning**, and **Output**. An agent span shows how its time splits into **Model**, **Tools**, and **Other**, which add up to its duration; tool calls that run at the same time count once. It also shows the tokens and the **Cost** of the model calls under it, with a note of how many there are. The cost is split into the same five parts when each priced model call under it has the split; read [Cost by token class](/reference/cost#cost-by-token-class). - **Scores**: the scores of the trace and the span, with the source and the reason of each. The root span always shows this section, with **Add score**. Read [Read scores on a trace](/evals/scores#read-scores-on-a-trace). - A section for the kind of span, such as **Model call** with the **Requested model**, **Response model**, **Provider**, **Finish reason**, and **Response ID**, or **Tool call**, **Agent**, or **MCP**. - **Input** and **Output**: the prompt and the reply. In **Output**, a model's reasoning, such as Anthropic thinking or Gemini thoughts, appears as **Reasoning** above the reply when it was captured. A tool call shows **Arguments** and **Result** instead. Where a section offers them, select **Pretty** for a formatted view or **JSON** for the stored value. -- **Events**: the span events and their attributes. +- **Events**: the span events, with the level and the attributes of each. - **Attributes**: the span attributes. -A **Truncated** badge marks a value that the panel shows only in part. +The panel shows a value of up to 2,000,000 characters. A **Truncated** badge marks a longer value, which the panel shows only in part. A **Truncated at source** badge in the panel header means that the SDK or integration cut the span's content before sending it: the span has `telemetry.dev.capture.truncated` set to `true`, or its input, output, or error ends with the SDK's `...[truncated]` marker. -If prompt and response capture is off for the environment, the **Input** and **Output** sections say that capture is off, and the span name is `[REDACTED]`. Read [What capture-off removes](/platform/privacy#what-capture-off-removes). +If prompt and response capture is off for the environment, the **Input** and **Output** sections say "Not captured. Prompt capture is off for the _environment_ environment." with a link to the project's privacy settings, and the span name is `[REDACTED]`. Read [What capture-off removes](/platform/privacy#what-capture-off-removes). If capture is on but the span has no input or output, the section says that capture is off in the SDK. ## Follow a conversation Select **Sessions** in the project sidebar to list conversations. A session groups the traces that share a session ID. To set one, read [Add user, session, and metadata](/sdk/typescript#add-user-session-and-metadata) for TypeScript or [Python](/sdk/python#add-user-session-and-metadata). -Select **24h**, **3d**, **7d**, or **30d** to set the time range. You can search by session ID or trace name and filter by agent, user, model, or environment. The list shows each session's **Agent**, **Model**, **Customer**, **Turns**, **Tokens**, **Cost**, and **Last active** time. +Select **24h**, **3d**, **7d**, or **30d** to set the time range. You can search by session ID or trace name and filter by agent, user, model, or environment. The list shows each session's **Agent**, **Model**, **Customer**, **Turns**, **Tokens**, **Cost**, and **Last active** time. Sessions are listed newest first by the start of their latest trace, so a session whose latest trace started earlier but ran longer can come after one with a later **Last active** time. Select a session to see its **Customer**, **Agent**, **Models**, **Started** time, **Duration**, **Tokens**, and **Cost**, a list of its **Turns**, and each turn of the conversation. Select **Open in Traces** to list the session's traces, or **Open trace** if the session has one trace. Select **Add to dataset** or **Add to review queue** to send the session to Evals. The session page also shows the [scores](/evals/scores#read-scores-on-a-session) of the session and of each turn. +The session page reads the first 4,000 characters of each stored input and output, so a long prompt or reply can stop short. When you open a tool run or a model's reasoning, the page loads its full value. To read a long prompt or reply in full, open the trace and select the span. + ## Read logs Select **Logs** in the project sidebar. The table shows **Date**, **Level**, **Entity**, **Message**, and **Data**. @@ -110,4 +115,4 @@ The level filter starts at `error`. You can also select `warn`, `info`, `debug`, The table loads the newest 100 matching log records from the last 30 days, or from the retention period if that is shorter. It has no further pages. The search box filters only the message previews in those loaded records. -Select a row to open the log details, with the full message, level, service, environment, the related trace, and the log's data. If the log has trace context, select **Trace** to open the trace with the log's span selected. +Select a row to open the log details, with the message, level, service, environment, the related trace, and the log's data. The details show the first 1,000 characters of the message, ending with `…` when it is longer, and the first 4,000 characters of the data, marked **Preview truncated** when it is longer. If the log has trace context, select **Trace** to open the trace with the log's span selected. diff --git a/docs/reference/cost.mdx b/docs/reference/cost.mdx index a219a55..fac5c3a 100644 --- a/docs/reference/cost.mdx +++ b/docs/reference/cost.mdx @@ -1,7 +1,7 @@ --- title: Cost calculation description: Learn how telemetry.dev calculates model cost from token usage and model prices. -lastModified: 2026-10-18 +lastModified: 2026-10-31 seo: title: "LLM Cost Calculation from Token Usage" description: "telemetry.dev calculates LLM cost at ingest from token usage and a model price snapshot. A valid cost value from your SDK overrides the server calculation." @@ -67,6 +67,24 @@ The prices below are illustrative. They match the `anthropic:claude-sonnet-4-5` The stored cost is `0.03765`. Adding reasoning tokens to this span would not change it, because they are already counted in the 1,500 output tokens. +## Cost by token class + +When the server calculates a span's cost, it also stores the part of the cost that comes from each class of token. The five parts add up to the cost: + +| Part | Tokens | Rate | +| --- | --- | --- | +| Input | Uncached input | `input` | +| Cache read | Cache-read input | `cachedInput`, or `input` | +| Cache write | Cache-creation input | `cacheWrite`, or `input`, and `cacheWrite1h` for [one-hour cache writes](#provider-specific-adjustments) | +| Reasoning | Reasoning tokens, which are part of the output | `output` | +| Output | Output minus reasoning | `output` | + +Image and audio tokens go to the part of their kind at their own rates, as in [Modality pricing](#modality-pricing). In the worked example, the parts are $0.009 of input, $0.0024 of cache reads, $0.00375 of cache writes, and $0.0225 of output. If 500 of the 1,500 output tokens were reasoning, $0.0075 of the output would move to reasoning, and the total would stay `0.03765`. + +Each part rounds down to eight decimal places, and the units left over go to the parts with the largest remainders, so the parts always add up to the stored cost. + +A span has no parts when its cost is a [client cost](#client-cost) or null, or when it kept a cost that the current prices no longer give. Spans stored before the parts were added, on October 31, 2026, have none. The [trace page](/platform/traces#read-a-span) shows the parts in the **Cost** of an agent span when each priced model call under it has them; otherwise it shows the cost alone. The [MCP tool](/platform/mcp-server#what-an-agent-can-read) `get_trace` returns them for each span. + ## Rounding and precision The server works with exact decimal values of the prices, not floating-point arithmetic. It rounds the final cost once, to the nearest 0.00000001 dollars (eight decimal places), and drops trailing zeros. For example, 7 input tokens at $3.00 per million is stored as `0.000021`. diff --git a/docs/reference/evals-api.mdx b/docs/reference/evals-api.mdx index 7e51b72..3ec94b0 100644 --- a/docs/reference/evals-api.mdx +++ b/docs/reference/evals-api.mdx @@ -1,7 +1,7 @@ --- title: Evals API description: Read dataset items, run experiments of your code, and send scores over HTTP, with request fields, limits, and error codes. -lastModified: 2026-10-30 +lastModified: 2026-10-31 --- The Evals API lets your code read the items of a dataset, send the outputs of an experiment, and send scores over HTTP. The TypeScript and Python SDKs use this API in `runExperiment` and `score`. Read [Experiments](/evals/experiments) and [Scores](/evals/scores) first. @@ -163,7 +163,7 @@ An error has a JSON body with a code and a message: | HTTP | Code | Cause | | --- | --- | --- | -| `400` | `invalid_request` | The body or a parameter is not valid. The message names the problem. | +| `400` | `invalid_request` | The body or a parameter is not valid. The message names the problem. Text in the body or a parameter cannot contain U+0000 or a lone UTF-16 surrogate, such as `\u0000` or `\ud800` in JSON. | | `400` | `decompression_failed` | The gzip body does not decompress. | | `401` | `invalid_api_key` | The key is missing, malformed, unknown, or revoked. | | `403` | `insufficient_scope` | The key does not have the scope of the route. | diff --git a/docs/reference/otlp.mdx b/docs/reference/otlp.mdx index f10d5aa..c64d195 100644 --- a/docs/reference/otlp.mdx +++ b/docs/reference/otlp.mdx @@ -1,7 +1,7 @@ --- title: OTLP ingest API description: Send OTLP/HTTP traces, logs, and metrics to telemetry.dev. -lastModified: 2026-10-29 +lastModified: 2026-10-31 seo: title: "OTLP/HTTP Ingest API (Protobuf and JSON)" description: "Send OpenTelemetry traces, logs, and metrics to telemetry.dev over OTLP/HTTP with protobuf or JSON. This page gives endpoints, authentication, limits, and error responses." @@ -199,6 +199,7 @@ telemetry.dev also records each rejection of an authenticated request on the pro | `401` | `invalid_api_key` | `Authorization must be Bearer td_live_xxx` or `API key was not accepted` | The key is missing, malformed, unknown, or revoked. | No | | `403` | `environment_mismatch` | `API key is scoped to another environment` | A resource environment, or the stored trace's environment, differs from the key's environment. | No | | `403` | `insufficient_scope` | `This API key cannot send telemetry. Create a key with Send telemetry access.` | The **Access** of the key does not have **Send telemetry**. Read [Select the access of a key](/platform/api-keys#select-the-access-of-a-key). | No | +| `403` | `project_not_accepting_telemetry` | `This project does not accept telemetry. Turn on Accept telemetry in its settings.` | **Accept telemetry** is off in the project's settings. This rejection is not recorded on the project. | No | | `409` | `telemetry_deleted` | `Telemetry was deleted` | The project's telemetry, or a trace in the batch, was deleted. | No | | `413` | `body_too_large` | `Request body exceeds limit` or `Decompressed request body exceeds limit` | The body is over 16 MiB as sent or after decompression. | No; split the batch | | `415` | `unsupported_media_type` | `Content-Type must be application/x-protobuf or application/json` | Missing or unsupported `Content-Type`. | No |