---
title: "Create a tracing key for a monitor"
method: POST
path: "/api/v1/checks/{id}/ingest-keys"
tags: ["ApiKeys"]
---

# Create a tracing key for a monitor

`POST /api/v1/checks/{id}/ingest-keys`

## Request

- Base URL: `https://app.lastping.dev`
- URL: `https://app.lastping.dev/api/v1/checks/{id}/ingest-keys`
- Auth: API key in header `X-Api-Key`

Mints a tracing key: an `ingest`-scoped key bound to this monitor. It
can send pings, traces, metrics and logs for this one monitor and
nothing else; every REST route refuses it. The plaintext `key` is
returned **exactly once**, in this response. Store it in a git-ignored
file or a helper script, never in committed code.

A `write` key may call this, unlike `POST /api/v1/api-keys`, because
the only thing it can mint is strictly weaker than the caller: the
scope is always `ingest`, `check_id` is always this monitor, and the
body accepts only `name` and `expires_at`. A `read` key and an
`ingest` key are refused with 403. A monitor of another project is
404, the same as a missing one.

The caps of `POST /api/v1/api-keys` apply unchanged: under a calling
key that expires, the new key cannot outlive it (a later `expires_at`
is 400 with `max_expires_at`; an omitted one inherits the caller's
expiry), and revoking the calling key revokes this one. A session
caller (the console) sends the CSRF header like every other write.

## Request body

- IngestKeyCreate: Body for `POST /api/v1/checks/{id}/ingest-keys`. Every field is optional and nothing else is accepted: the scope is always `ingest` and the key is always bound to the monitor in the path, so a body naming `scope` or `check_id` is refused with 400.
  - `name` string: Label for the key. Defaults to "Tracing:" followed by the monitor's name.
  - `expires_at` string, date-time: Optional RFC 3339 expiry, in the future. Capped by the calling key's own expiry exactly as `POST /api/v1/api-keys` caps it: a later value is refused with 400 and `max_expires_at`, and an omitted value under an expiring key inherits that key's expiry.

## Response `201`

Tracing key created. `key` is the plaintext credential, shown exactly once; `scope` is `ingest` and `check_id` is this monitor.

- ApiKeyCreated: An API key returned by the API. The plaintext key value is NEVER included here — only the non-secret `prefix` is returned, so this shape is used for both list and the non-secret half of create.
  - `id` string, uuid, required: Unique API key identifier.
  - `name` string, required: Human-readable label for the key.
  - `prefix` string, required: First 10 characters of the key — a non-secret identifier shown in place of the full value.
  - `created_at` string, date-time, required: RFC 3339 UTC timestamp when the key was created.
  - `expires_at` string, date-time: RFC 3339 UTC expiry timestamp, or omitted for a key that never expires.
  - `last_used_at` string, date-time: RFC 3339 UTC timestamp of the most recent request this key authenticated. Omitted if the key has never been used since this field was added — never rendered as a zero/epoch time.
  - `last_used_surface` 'mcp' | 'terraform' | 'api' | 'ingest': Which client surface last used this key, omitted if unknown. `ingest` means the latest use was sending telemetry (traces, metrics or logs); telemetry use is recorded about once a minute per key, so `last_used_at` can trail the newest export by up to a minute. For `mcp`, `terraform` and `api` the value is best-effort and spoofable: derived from the caller-controlled `User-Agent` header on the authenticating request, not from any cryptographic or protocol-level signal. Useful for an honest "did my client ever successfully authenticate?" indicator — never use it for authorization or access control.
  - `scope` 'read' | 'write' | 'admin' | 'ingest', required: What this key is permitted to do. Always present. Unlike `last_used_surface` above — which is a spoofable hint derived from a caller-supplied header — this is the value the server actually checks. `ingest` sends telemetry only and cannot call this API.
  - `check_id` string, uuid: The one monitor an `ingest` key is bound to. Omitted for an unbound key and for every key of another scope.
  - `created_by_key_id` string, uuid: The API key that minted this one, omitted for a key created from the dashboard (which has no parent key) or whose parent has since been deleted. **Revoking a key revokes every key below it in this chain.** A key minted by a key minted by the key you delete goes with it, all at once. A key created from the dashboard is never below anything and is unaffected.
  - `key` string, required: The plaintext API key. Store it immediately — it cannot be retrieved again.

## Other responses

- `400`: id is not a valid UUID; the body has a field other than `name` and `expires_at` (`INVALID_BODY`); `expires_at` is not in the future; or it exceeds the calling key's own expiry (`expires_at may not exceed the creating key's own expiry`, with `max_expires_at`).
- `401`: Missing or invalid API key.
- `403`: The API key authenticated, but its scope does not reach this operation. The problem body carries `required_scope`: the tier the operation needs. Re-mint the key at that scope (Settings, `POST /api/v1/api-keys`, or the `create_api_key` MCP tool) rather than retrying — the refusal is deterministic and a retry will be refused identically.
- `404`: Check not found in this project.
- `429`: Too many requests. The per-principal fixed-window rate limit has been exceeded. Retry after the number of seconds indicated by the `Retry-After` response header. The problem body's `code` is `RATE_LIMITED`. It names this limiter specifically, so a client can tell it apart from the application-level throttles that also answer 429 with their own codes and their own, much longer, `Retry-After` values (`TEST_PING_RATE_LIMITED`, `TOO_MANY_ATTEMPTS`). Back off globally on `RATE_LIMITED`; back off on the one operation for the others. The principal is the API key for a key-authenticated request and the USER for a browser session, so every tab one person has open shares one budget.

---

[API](https://skmtc.dev/lastping/apis/lastping-management-api.md) · [All operations](https://skmtc.dev/lastping/apis/lastping-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lastping/apis/lastping-management-api/revisions/bbc6eda91c46?raw)
