Skip to content

Trace API

POST /panopticon/trace — the RP reports the result of a tool call to logi's Panopticon.

Authentication

Panopticon uses a separate credential (the Panopticon PAK). It does not reuse the user's OAuth token (JWT) for telemetry, which avoids audience confusion.

Simple mode (default) ✓ Implemented

http
Authorization: Bearer pano_pak_...

It verifies only that the PAK hash matches. This is the default for every application. (See PakAuthenticator#authenticate! — based on the panopticon_pak_secret_encrypted column.)

HMAC strict mode 🔬 (roadmap)

Not implemented — design spec

The require_trace_hmac flag, pak_secret issuance, and X-Panopticon-Signature / X-Panopticon-Timestamp header verification this section covers do not exist in the codebase yet (audited 2026-05-15). The OauthApplication model has no such columns or methods, and Panopticon::TracesController has no HMAC branch or timestamp-tolerance check.

If you want defense against body tampering, work around it with PAK rotation + HTTPS pinning + an RP-side local buffer hash. For inquiries about the HMAC strict mode implementation, reach us at support@1pass.dev.

When an application's require_trace_hmac flag is on, these additional headers are required (planned):

http
Authorization: Bearer pano_pak_...
X-Panopticon-Signature: <hex(HMAC-SHA256("<timestamp>.<body>", pak_secret))>
X-Panopticon-Timestamp: <unix epoch seconds>

The canonical string is "<timestamp>.<body>" (timestamp + dot + raw body). Verification:

  • The difference between X-Panopticon-Timestamp and the server time is ≤ ±5 minutes.
  • HMAC-SHA256("<timestamp>.<body>", pak_secret) matches the signature.

Sample (Node.js):

js
import crypto from "node:crypto";
const ts = Math.floor(Date.now() / 1000);
const body = JSON.stringify(payload);
const sig = crypto
  .createHmac("sha256", PAK_SECRET)
  .update(`${ts}.${body}`)
  .digest("hex");
fetch("https://api.1pass.dev/panopticon/trace", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${PANOPTICON_PAK}`,
    "X-Panopticon-Signature": sig,
    "X-Panopticon-Timestamp": String(ts),
    "Content-Type": "application/json",
  },
  body,
});

Payload schema

jsonc
{
  "event_id": "550e8400-e29b-41d4-a716-446655440000", // REQUIRED, RP-generated UUID v4
  "client_id": "logi_f31b6962aef3",                    // REQUIRED, for verification (must match the PAK)
  "tool": "memorize_fact",                             // REQUIRED, the name of the tool called
  "scope_used": "agent:memory.write",                  // RECOMMENDED, the value used from the JWT scope claim
  "status": "ok",                                      // REQUIRED, ok | error | denied | hitl_pending
  "started_at": "2026-05-09T10:11:12Z",                // REQUIRED, ISO 8601 UTC
  "duration_ms": 42,                                   // OPTIONAL, tool execution time
  "error_code": null,                                  // RECOMMENDED when status=error
  "user_sub": "user_xyz",                              // OPTIONAL, RP self-reported — logi does not verify it
  "metadata": {                                        // OPTIONAL, free-form jsonb field (no PII)
    "model": "claude-sonnet-4-6",
    "session_id": "..."
  }
}

Field constraints

FieldTypeValidation
event_idUUID v4 stringMatches the RFC 4122 format, unique per application
client_idstringMatches the client_id of the application the PAK was issued for (400 on mismatch)
toolstring1–128 chars, alphanumeric and ._-:
scope_usedstringMatches the OauthScope NAME_PATTERN (if absent, logged but not enforced)
statusenum stringOne of ok / error / denied / hitl_pending
started_atISO 8601 UTCWithin ±1 hour of the current time (clock skew tolerance)
duration_msinteger ≥ 0At most 600000 (10 minutes)
metadatajsonb16KB or less, must not contain PII (RP's responsibility)

Responses

Success

HTTPSituationBody
202 AcceptedNew ingestion succeeded{"event_id":"...","status":"accepted"}
200 OKSame (app, event_id) is a duplicate — ignored{"event_id":"...","status":"duplicate"}

Errors

HTTPerror codeMeaning
400invalid_payloadMissing required field / format mismatch
400client_id_mismatchbody client_id ≠ the PAK's owning application
401invalid_pakPAK signature/hash mismatch, or rotated
401invalid_signatureHMAC strict mode is on but the signature is missing/mismatched
401expired_timestampHMAC strict mode is on but the timestamp is outside ±5 minutes
403panopticon_disabledPanopticon is disabled for the application
429rate_limitedPer-PAK throttle exceeded (default 1000/min)
503service_unavailableA transient logi-side outage — the RP should buffer locally and resend

Error response format:

json
{
  "error": "invalid_payload",
  "error_description": "event_id is missing",
  "documentation_url": "https://docs.1pass.dev/panopticon/trace-api"
}

Rate limit

  • Default: 1000 traces/minute, per PAK (rack-attack throttle).
  • Per-application override: OauthApplication#trace_rate_limit_override 🔬 — a design spec, no column yet (2026-05-15). All applications share the same default.
  • On exceeding it: 429 + a Retry-After header.
  • No quota enforcement in the beta — the rate limit is only a per-second throttle; the monthly limit is shown but not enforced.

Idempotency and resending

On a logi outage or network error, the RP should buffer traces locally and, after recovery, resend with the same event_id. The server:

  • On finding the same (oauth_application_id, event_id), returns 200 OK + status:"duplicate".
  • Does not double-count in the usage aggregates.

The user_sub trust model and its limits

user_sub is an RP self-reported field. logi does not verify this value beyond PAK verification. If a wrong value comes in:

  • The Panopticon console's user filter becomes inaccurate.
  • A HITL approval may be delivered to the wrong user.

→ The RP must populate user_sub only with a verified user identifier from its own database.

Defending against payload tampering

  • HMAC mode: defends against body tampering — 🔬 design stage (see the HMAC strict mode roadmap above). For now, work around it with TLS + PAK rotation + an RP-side local hash.
  • PAK rotation ✓ Implemented: on suspected exposure, rotate immediately in the console. After rotation, the old PAK is invalid (the panopticon_pak_secret_encrypted column is updated).
  • PII masking: rather than putting raw user input into metadata, summarize or hash it (the RP's responsibility — the logi server does not verify it).

Next

Identity가 제품의 신뢰를 만듭니다.