Skip to main content
POST
/
v1
/
snapshot
curl --request POST \
  --url https://api.jdcodec.com/v1/snapshot \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --header 'X-JDC-API-Version: <x-jdc-api-version>' \
  --data '
{
  "session_id": "9c1b2f6e-0b8e-4a77-9cfd-3e3f7b5e8d21",
  "task_id": "a7d19e44-31f6-4a02-8f9b-0c2a5fbc11d3",
  "step": 7,
  "url": "https://example.com/admin/catalog/product/edit/id/[REDACTED_ID]",
  "snapshot_yaml": "- role: main\n  ref: \"#main\"\n  children:\n    - role: button\n      name: Save\n",
  "client_redacted": true,
  "redaction_stats": {
    "email": 2,
    "CC_GENERIC": 1
  }
}
'
{
  "frame_type": "P",
  "compressed_output": "P7: [edits] main.children[4] …",
  "compression_stats": {
    "input_chars": 40123,
    "output_chars": 5432,
    "codec_ms": 9.1
  }
}

Authorizations

Authorization
string
header
required

API key in two parts separated by a dot, sent as a single bearer:

  • api_key_id — public, stable, jdck_-prefixed lookup handle. Safe to log and reference in support conversations.
  • api_key_secret — opaque high-entropy string. Shown to the customer once at issuance and never again. Server stores only its hash.

Example:

Authorization: Bearer jdck_9f3a2b7c8d1e4f05.BASE32URL_SECRET

Headers

X-JDC-API-Version
enum<string>
required

Always 1 for v1. Missing or mismatched value returns 400 version_unsupported.

Available options:
1
Example:

"1"

X-Request-Id
string<uuid>

Optional client-supplied UUID v4. The server echoes this header in the response and in every error body. If absent or malformed, the server assigns one.

Accept-Encoding
string

gzip recommended. Snapshot bodies and compressed output are JSON and benefit from response compression on slow links.

Example:

"gzip"

Body

application/json
session_id
string<uuid>
required

Client-generated UUID v4. Stable across every snapshot in the session.

task_id
string<uuid>
required

Client-generated UUID v4. Stable across every snapshot in a single task. Tasks are fully contained in one session.

step
integer
required

0-indexed step within the session. Must increase monotonically within a session; out-of-order returns 400 step_out_of_order.

Required range: x >= 0
url
string
required

Page URL at the time of snapshot. On the default path it is already redacted by the connector's Privacy Shield — values such as IDs, tokens, and other PII-shaped substrings are replaced with bracketed tokens. Under an accepted bypass (client_redacted: false + privacy_shield_bypass: true) it is the raw URL; the service structurally minimizes it before persisting (host + path + query parameter names; query values, fragment, and userinfo dropped).

snapshot_yaml
string
required

Playwright-MCP YAML snapshot, UTF-8 encoded. Already redacted on the default path; raw under an accepted bypass. Maximum decoded size 2 MiB; larger snapshots return 413 payload_too_large.

Maximum string length: 2097152
client_redacted
boolean
required

Audit signal that the connector's on-device Privacy Shield has run. true on the default path — missing or false returns 400 privacy_shield_missing unless the bypass conditions below are met.

false is accepted only under the Privacy Shield bypass (D018): the request must also carry privacy_shield_bypass: true and the authenticated key must be provisioned with privacy_shield_bypass_allowed: true. Either missing returns 400 privacy_shield_missing. See the bypassUnredacted example.

redaction_stats
object
required

Category → count map. Empty {} means the Privacy Shield ran and matched nothing. Counts only — never the redacted values.

Examples:
{}
{ "email": 2, "CC_GENERIC": 1 }
{ "phone": 1, "address": 4 }
privacy_shield_bypass
boolean

Optional. Set true alongside client_redacted: false to opt into an unredacted send. Additive — omitting it (the default path) is unchanged behaviour. Accepted only when the authenticated key is provisioned for bypass; otherwise 400 privacy_shield_missing. When true, redaction_stats is {} and both url and snapshot_yaml are raw.

agent_llm
object

Optional. Customer's agent-LLM metadata, announced on the first snapshot of a session; ignored on subsequent snapshots of the same session (the codec service stores it on first sight).

Used to pick the correct tokenizer for token-aware features. When absent, the codec falls back to tiktoken-fallback with approximate counts. Char counts are unaffected by this field.

Response

Snapshot processed. The connector splices compressed_output into its agent's tool response, or — on frame_type: "pass-through" — reuses the snapshot_yaml it sent.

frame_type
enum<string>
required

Frame type emitted by the codec. The single-letter values are the wire encoding; the human-readable meaning of each:

  • I — keyframe. Full snapshot, returned on the first step of a session and on forced refreshes (e.g. URL change). Equivalent in size to the original snapshot.
  • P — delta. Only what changed since the previous step. Typically a small fraction of the snapshot size.
  • P-nochange — no meaningful change since the previous step. The response carries a sentinel header (=== No Changes (Step N) ===, with an optional , K in a row suffix on consecutive nochanges) plus a single short recap line summarising the URL, the actionable-now element counts on the page, and up to three recently-changed elements as a small ref anchor. The recap helps an agent stay oriented across a stretch of no-op turns without requesting a fresh snapshot.
  • pass-through — the codec chose not to compress this snapshot (e.g. a full-table scan where compression wouldn't help). The connector reuses the snapshot_yaml it sent in the request. compressed_output is omitted from the response body.
Available options:
I,
P,
P-nochange,
pass-through
compression_stats
object
required
compressed_output
string

The codec-emitted replacement for snapshot_yaml.

  • Required when frame_type is I, P, or P-nochange.
  • Absent when frame_type is pass-through — the connector reuses the snapshot_yaml it sent in the request.
token_stats
object

Optional. Absent in the v1 steady-state path because tokenization runs asynchronously after the response is sent. See TokenStats for the full lifecycle rationale.

The authoritative per-snapshot token data lives on the usage_events row keyed by (session_id, step); the connector can fetch it later via the usage-report endpoint.