Ingest OTLP traces for a run (Bearer-authenticated)
Accepts one OTLP ExportTraceServiceRequest (protobuf or its JSON mapping) and enqueues its spans to be stored. Model and provider names are stored up to 200 bytes. This is the documented path: a project API key with ingest, write or admin scope in the Authorization: Bearer header names the project; the lastping.monitor_id resource attribute names which check (required unless the key is bound to a monitor).
Monitor-bound keys: an ingest key minted with a check_id is bound to that monitor. Its spans always land on that monitor, so lastping.monitor_id may be omitted; a payload that names a different monitor is 400.
Secrets are redacted before anything is stored. Every string attribute value, span name and status message is scanned at ingest and each secret-shaped value is replaced by [REDACTED:<class>] (see the check's trace_content). By default (trace_content: dropped) prompt and command content is removed entirely; a monitor set to redacted stores it, redacted.
Auth: Authorization: Bearer lp_…. The key must be unrevoked, unexpired, and scoped ingest, write or admin. This endpoint enforces scope unconditionally, regardless of how the management API rolls out scope enforcement: a new endpoint starts strict. No X-Api-Key form; the monitor-URL alternative below is this route's only unauthenticated option.
Correlation: lastping.monitor_id (uuid) names the check and is required on this form (400 when missing). It is read from the resource attributes, or from a span attribute when no resource carries one (for exporters with no resource attributes); the resource wins when both are present. lastping.run_id is optional. With it, every span of the request joins that run (the rid the run's pings already carry). Without it, each trace in the request becomes its own run, with rid trace- followed by the hex trace id, listed by GET /api/v1/runs with traced: true. Spans are never guessed onto a run by time. A run made from a bare trace never opens an incident and never changes the monitor's status.
Content-Type: application/x-protobuf or application/json (415 otherwise). Content-Encoding: gzip is accepted and decompressed under the same size cap as an uncompressed body.
Caps (enforced before enqueue): body ≤ 1 MiB decompressed (413 over); ≤ 500 spans per request (400 over); span name ≤ 256 bytes (truncated, not rejected); attributes ≤ 32 KiB per span (excess dropped, truncated set on the span, not rejected); ≤ 2,000 spans per run across every request (further spans dropped and counted in spans_dropped, not rejected — this cap is enforced when the spans are stored, after this endpoint answers). A span that starts more than an hour after ingest received it is dropped and counted in dropped; the rest of the request is kept. Rate limit: 3,600 requests/hour/project, a bucket entirely separate from the ping rate limits, so a chatty tracer cannot starve heartbeats (429 with Retry-After: 60). LastPing reads a few OTLP exports at once; past that an export is refused 429 with code: "OTLP_BUSY" and Retry-After: 5 before its body is read. Pings are never refused this way.
Durability: identical rule to pings — an accepted request is 202 only after the enqueue to the spans queue succeeds; a queue failure is 503, never a silent ack. Every span field is third-party text: render it as text, never interpret it as markup.
Request
- Base URL: https://ping.lastping.dev
- URL: https://ping.lastping.dev/v1/traces
- Auth: HTTP bearer
Request body
The OTLP JSON mapping of ExportTraceServiceRequest.
Response
Accepted and enqueued.
Example response
{
"accepted": 42
}Changes
No recorded changes to this operation across all 2 revisions of this API.