Skip to main content
pikopod up serves two listeners. Each carries a small control surface next to the traffic it handles. When a token is configured, every request to either listener must carry it in X-Pikopod-Token. On loopback with no token, the sandbox control plane is open, because it controls a fake and never a provider. All control responses are JSON with content-type: application/json; charset=utf-8.

Sandbox listener (:4600)

Traffic to a sandbox goes to /<name>/.... The control plane lives under /_pikopod/v1/sandboxes/<name>/. The v1 segment is the stable contract the test helpers are written against; every response carries x-pikopod-api: v1. The unversioned paths, /_pikopod/v1/sandboxes/<name>/..., keep working as aliases for one release. A fork’s control plane lives under its own name, /_pikopod/v1/sandboxes/<name>--<token>/, and resolves modes and verification against the parent’s spec and seed.

Rules

PUT replaces the live set at once and does not write the rules file; pikopod rule add and rule drop write the file and then push it here, so the file stays the source of truth across restarts. See Rules.

Seed, snapshot, reset and forks

A fork is served at /<name>--<token>/ and has its own control plane under /_pikopod/v1/sandboxes/<name>--<token>/. Seeding a fork does not change the parent’s seed file. See Running.

Faults

A fault rule:
kind is one of error, latency, hang, slow_body, rate_limit, connection_reset, empty_response, random_data_then_close, malformed_response, wrong_content_length, duplicate_webhook, drop_webhook, reorder_webhook, delay_webhook. Non-webhook kinds need method and path (the path template as in the spec). rate_limit is armed as an error with status 429; error with no status becomes 500. probability defaults to 1. body (a JSON object or array) and headers are optional and apply to error; without body the fault answers with the spec’s declared example for that status when there is one, else no body. Without method and path the server answers 400 {"message":"method and path are required"}. See Faults.

Requests journal

Each entry carries the sequence number, method, path, matched template, status, and redacted headers, query and body. evicted counts older entries the bounded journal dropped. scopes.live counts the scopes the sandbox currently keeps, at most 256, and scopes.evicted the ones it forgot to make room. See Request journal.

Mode

DELETE clears every fault on the sandbox and removes the stored mode. A scenario that has no standing state is refused with 400 and the reason. See Modes. Without scope, only the requests that carried no scope header are judged. See Scoped, or global.

Webhooks

Only events the spec declares can be emitted. See Webhooks.

Errors

Request bodies are read up to 1 MiB.

Every endpoint, exercised

Each example below is the real request and response from one run of the endpoint, generated by a test in the repository so this section cannot drift from the binary. The sandbox was imported from the example spec with seed docs; the client traffic between the mode and its verification was three POST /charges under one idempotency key.

Rules: read the live set

200

Rules: replace the live set

200

Faults: arm one

201

Faults: list standing faults

200

Faults: clear matching faults

200

Mode: enter a scenario’s standing state

201

Mode: verify what the client sent

200

Mode: show the standing mode

200

Mode: clear it

200

Requests: the journal

200

Requests: reset the journal

200

Webhooks: deliveries so far

200

Webhooks: emit an event the spec does not declare

400

Seed: store resources

200

Snapshot: mark a point

200

Restore: return to it

200

Reset: back to the seeded state

200

Fork: a fresh copy for one test

201

Forks: the live copies

200

Fork: delete it

200

Agent listener (:4700)

Traffic to an upstream goes to its listen route, /<upstream>/... by default. Anything that matches no upstream answers 404.

Health

GET /healthz is public for liveness. Without a token, or with a token and the header, it returns the full payload:
With a token set and no header it answers 200 {"status":"ok"} only, so a load balancer can poll it without being handed your upstream inventory. spec_watch appears when a watcher is armed. The divergence_* counters are described under Divergence and the webhooks_* counters under Incidents.

Inbound webhooks

POST /hooks/<upstream> exists for every upstream with a webhooks.receiver. It needs no token and ignores the loopback Host guard, since the provider delivering to it cannot carry either; it forwards to the configured receiver and nothing else.

Acknowledge and accept

agent ack silences a fingerprint until its diff changes. agent accept refreezes the endpoint’s baseline from live traffic and acknowledges, so the drifted behaviour becomes the new normal. Unknown fingerprints answer 404. See Alerts.

Headers the agent handles

X-Pikopod-Token is stripped before anything is forwarded, in every configuration. When an upstream cannot be reached, the agent answers 502 with X-Pikopod-Error: upstream-unreachable and never retries. See Headers.