Five minutes to a verified evidence record¶
Copy a key, seal a record, read the receipt, see it in the control plane, verify it offline. Everything on this page runs against the live API.
What this is for
Your AI acts. This is the proof of what happened.¶
Your AI drafts and does consequential things — files documents, sends client work, releases billing entries. Planisphere is the missing evidence layer around those acts: gate holds a consequential act until a human signs off, the act and the sign-off seal into a tamper-evident receipt, and anyone — an auditor, a client, opposing counsel — can verify that receipt forever, offline, without trusting you or us. You wrap one boundary in your code; you get an audit trail of your AI's actions as a side effect.
Impatient? Jump to the complete example — a 50-line agent wrapper you can run in two minutes.
Step 1
Get your key¶
Get a free test key in the console — work email + organization, no card, minted in place. The key starts with ps_test_, is shown once, and is limited to one sandbox per email (a repeat email returns 409 with an upgrade pointer). Free allowance: 100 sealed actions.
Step 2
Make your first call¶
Auth is a single header: X-Planisphere-Key (a Authorization: Bearer token also works). Gate an action — the API decides, and seals the decision as evidence:
Note
Pack context has a named envelope: the law pack reads law_context (matter_band, tool_id, doctrine_anchor…); other packs read context + action_type. GET /v1/packs lists each pack's exact required fields.
curl -sS -X POST https://api.planisphere.ooo/v1/gate \
-H "X-Planisphere-Key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"pack":"law","proposed_action":"File this motion with the court."}'
Note
Every pack and its exact request shapes are machine-readable at GET /v1/packs — the honest source for what each gate accepts.
Prefer an SDK?
Official thin clients (no runtime dependencies), live on PyPI and npm — see the SDK guide.
pip install planisphere
from planisphere_sdk import Planisphere
ps = Planisphere(api_key="ps_test_...")
decision = ps.gate(
pack="law",
proposed_action="File this motion with the court.",
idempotency_key="run-42", # safe to retry - returns the original result, meters once
)
npm install planisphere-sdk
import { Planisphere } from "planisphere-sdk";
const ps = new Planisphere("ps_test_..."); // key is positional, not an options object
const decision = await ps.gate({
pack: "law",
proposed_action: "File this motion with the court.",
law_context: { matter_band: "litigation", tool_id: "harvey" },
idempotencyKey: "run-42", // safe to retry - returns the original result, meters once
});
// Record the human call on a routed action, then prove the receipt:
// every gate/review/record response carries an in-band verify_request.
await ps.recordReview({
pack: "law",
action_key: decision.action_key,
reviewer: "partner@firm.example",
decision: "approved",
});
const check = await ps.verify(decision.verify_request); // { verified: true, ... }
Step 3
Read the response¶
You get a decision (allow, needs_review, or blocked), an action_key, and an evidence_packet — the packet is your sealed record: hash-committed, signed, and independently checkable.
Note
A fresh sandbox typically returns needs_review — the gate routed the action to human review, and the record sealed either way. That routing is the product working; allow comes once your tenant policy allowlists the action type.
Note
Sandbox receipts sign with a public, reproducible dev key (dev_key:true) and a different public key than production — they are provably non-production and must never be presented as production evidence. Production keys sign with a managed, non-exportable key.
Also: attest completed acts
Record what already happened¶
The gate asks permission before an act. When the act is already done — an output was marked, a disclosure was shown — attest it with POST /v1/record using a record-verb pack event (the eu-ai-act and ca-sb942 duty vocabularies): terminal "status": "recorded", a sealed evidence packet, no review routing. Send hash commitments, not content (POST /v1/record/batch takes an array for volume):
curl -sS -X POST https://api.planisphere.ooo/v1/record \
-H "X-Planisphere-Key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"pack":"eu-ai-act","event_type":"output_marked",
"occurred_at":"2026-07-22T17:03:11Z",
"source_payload":{"content_sha256":"<sha256-of-your-output>"},
"metadata":{"marking_techniques":["signed_metadata","imperceptible_watermark"],
"marking_payload_ids":["c2pa:manifest-1"],
"model":"imagegen-large","model_version":"4.2.0",
"detection_check_result":"pass"}}'
Note
Payload retention: Planisphere stores hash commitments only — retain your payload to re-prove WHAT was recorded. Every record response repeats this in its payload_retention field.
Note
Batch shape: POST /v1/record/batch takes a bare JSON array of record objects — each item is the exact single-record body, no wrapper key:
curl -sS -X POST https://api.planisphere.ooo/v1/record/batch \
-H "X-Planisphere-Key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '[{"pack":"eu-ai-act","event_type":"output_marked", ...},
{"pack":"eu-ai-act","event_type":"disclosure_rendered", ...}]'
Step 4
See it in the control plane¶
Open the control plane and paste your key into the key field (replace the placeholder value). Run gates, browse receipts, manage keys, and export your audit trail. From code, fetch any record by its key:
curl -sS https://api.planisphere.ooo/v1/records/ACTION_KEY \
-H "X-Planisphere-Key: ps_test_YOUR_KEY"
Note
Records are fetched by action_key — hold onto the keys your gates return. For a period, export sealed records with GET /tenant/exports/records?from=&to=&cursor= (filters are always applied — unknown query parameters are rejected, never silently ignored), then POST the action keys to /evidence-packets/seal-bundle/batch as a wrapped object — {"action_keys":["law:...","eu-ai-act:..."]}, unlike the bare array /v1/record/batch takes — for one offline-verifiable evidence package.
Note
GET /v1/records/ACTION_KEY/inclusion-proof returns the canonical roll-up inclusion proof for any record. Records anchor into a canonical epoch on the hourly roll-up, so a record sealed moments ago returns an honest 409 until the next epoch — the body carries epoch_cadence, a next_epoch_hint, and an estimated_next_epoch_at timestamp telling you when to retry.
Step 5
Verify the receipt — without trusting us¶
Combine your evidence_packet with three fields from the gate response (decision, payload_hash, review_route) and POST to /v1/verify:
curl -sS -X POST https://api.planisphere.ooo/v1/gate \
-H "X-Planisphere-Key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"pack":"law","proposed_action":"File this motion with the court."}' > /tmp/gate.json
python3 -c 'import json; d=json.load(open("/tmp/gate.json")); p=d["evidence_packet"]; \
print(json.dumps({"action_key":p["action_key"],"href":p["href"],"status":p["status"], \
"packet_hash":p["packet_hash"],"seal":p["seal"],"decision":d["decision"], \
"payload_hash":d["payload_hash"],"review_route":d.get("review_route")}))' > /tmp/verify.json
curl -sS -X POST https://api.planisphere.ooo/v1/verify \
-H "X-Planisphere-Key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" -d @/tmp/verify.json
Expect "verified": true with every seal check itemized — signature, hashes, and key identity, each recomputed.
For fully offline verification: GET /v1/verify/kit returns the recipe (fields, hashes, and checks — no key material required), and planisphere.ooo/verify verifies seal-bundle files entirely in your browser; the record data never leaves the tab. Don't trust us — re-check it yourself.
Put it together
A complete example: an AI assistant that releases drafted work¶
The scenario every team recognizes: an agent drafts client-facing output and releases it. This file adds the evidence layer — the release is gated, the human sign-off is sealed, and the receipt verifies. Download it (quickstart_agent.py), run it with your test key, and read the four lines it prints:
"""An AI assistant that releases drafted work — with evidence.
Scenario: your AI drafts client-facing output (a filing, an email, a billing
entry). Today it just... goes out. This example adds the missing layer: every
release is gated, human sign-off is sealed, and anyone can verify the record
later without trusting you or Planisphere.
Run it: pip install planisphere && python quickstart_agent.py ps_test_YOUR_KEY
"""
import sys
from planisphere_sdk import Planisphere, PlanisphereNeedsReview
def release_draft(ps: Planisphere, draft_id: str, summary: str) -> dict:
"""The one change to your agent: gate the release instead of just doing it."""
try:
decision = ps.require_allow(
pack="law",
proposed_action=f"Release drafted document {draft_id}: {summary}",
surface="agent",
source_key=f"agent:draft:{draft_id}",
law_context={"matter_band": "active-litigation", "tool_id": "my-agent"},
idempotency_key=f"release-{draft_id}", # retries never double-bill
)
except PlanisphereNeedsReview as exc:
decision = exc.decision
print(f" paused: routed to {decision['review_route']} — a human decides")
# In production you'd stop here and resume on webhook/poll. For the
# demo, the supervising human approves right now:
ps.record_review(pack="law", action_key=decision["action_key"],
reviewer="supervising-partner", decision="approved")
print(" approved by supervising-partner — sign-off sealed")
return decision
def main() -> int:
ps = Planisphere(sys.argv[1]) # key is positional
decision = release_draft(ps, "draft-014", "Motion to compel, Johnson v. Dunn")
# The part your auditor cares about: the receipt proves itself.
verdict = ps.verify(decision["verify_request"])
print(f" receipt verified: {verdict['verified']} "
f"(key_status: {verdict['key_status']})")
print(f" keep this action_key for your records: {decision['action_key']}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Expected output (this exact run was executed against the live API before this page shipped):
paused: routed to legal-ops:policy-review — a human decides
approved by supervising-partner — sign-off sealed
receipt verified: True (key_status: sandbox)
keep this action_key for your records: law:proposed-action:…
Note
In production the agent stops at "paused" and resumes when your reviewer approves — via the webhook events or by polling the record. The demo approves inline so you can see the whole loop in one run. Same pattern in TypeScript: require_allow → catch PlanisphereNeedsReview → recordReview → verify.
When you're ready
Go to production¶
Track your allowance anytime: GET /tenant/usage returns actions used, your cap, what remains, and a warning as you approach it. Upgrade with the same email at signup — paid checkout rotates your sandbox tenant to a ps_live_ key and preserves its history. Usage-metered: 1¢ per credit, capped per action.
Go deeper
Integration guides¶
Live guides for the SDKs, Python/JavaScript middleware, LangChain, OpenAI Agents, Slack, ServiceNow, and signed event webhooks.
Next: start with the Client SDKs — the thinnest path from this page to production code.
U.S. patents pending · © 2026 PlanisphereUS, Corp. · Delaware C Corp · API reference · Pricing · Integration guides