Skip to content

Client SDKs

Official thin clients for the Planisphere Evidence API. Both wrap the same HTTP surface — gate an action, get a signed offline-verifiable receipt, route what needs a human — with typed errors and the decision signals. No runtime dependencies (Python: standard library; Node: built-in fetch, Node 18+).

The released clients are available from PyPI and npm. As of October 21, 2026, PyPI has 0.2.0 and npm has 0.1.0. The 0.1.0 clients cover the gate, review and verification methods below; for completed-event recording from Node, use the HTTP quickstart or a supported connection helper. verify_local / verifyLocal arrive in 0.3.0.

Python

pip install planisphere
from planisphere_sdk import Planisphere, PlanisphereNeedsReview, PlanisphereBlocked

ps = Planisphere(api_key="ps_live_...")

decision = ps.gate(
    pack="law",
    proposed_action="File this motion with the court.",
    surface="agent",
    source_key="agent:run:42",
    law_context={"matter_band": "litigation", "tool_id": "harvey"},
    idempotency_key="run-42",   # safe to retry — returns the original result, meters once
)

if decision["decision"] == "allow":
    ...  # proceed, and keep decision["evidence_packet"] as your receipt

Prefer exceptions? require_allow raises PlanisphereNeedsReview / PlanisphereBlocked unless the action is allowed.

Node / TypeScript

npm install planisphere-sdk
import { Planisphere, PlanisphereNeedsReview, PlanisphereBlocked } from "planisphere-sdk";

const ps = new Planisphere("ps_live_...");

const decision = await ps.gate({
  pack: "law",
  proposed_action: "File this motion with the court.",
  surface: "agent",
  source_key: "agent:run:42",
  law_context: { matter_band: "litigation", tool_id: "harvey" },
  idempotencyKey: "run-42",   // safe to retry — returns the original result, meters once
});

if (decision.decision === "allow") {
  // proceed, and keep decision.evidence_packet as your receipt
}

requireAllow throws the decision signals instead of returning them.

What both clients cover

  • gate / require_allow (requireAllow) — gate an action, with an optional idempotency key so retries return the original result and meter once.
  • verify and verify_kit (verifyKit) — check a receipt, or fetch the offline verification recipe.
  • From 0.3.0, verify_local (verifyLocal) — check a receipt on your own machine with no network call, against a saved copy of the published keys. The rules are in the seal contract.
  • get_record (getRecord) — fetch a stored evidence packet.
  • record_review / review_queue (recordReview / reviewQueue) — the human review loop.
  • Typed errors: PlanisphereError → PlanisphereAuthError (401/403), PlanisphereRateLimited (429, with retry-after), and the decision signals PlanisphereBlocked / PlanisphereNeedsReview (both carry .decision).

Free plan

Create a free workspace, verify your email, and create a key in the console's Keys tab. No card is required. The free plan includes 1,000 credits every month, and its records are sealed with the production key. At the allowance, recording pauses until the 1st; add a card on Billing to keep recording past it. Records sealed earlier with the sandbox key (dev_key: true) keep their original signatures and stay non-production.

Webhooks

To receive events (record.sealed, receipt.anchored, verify.failed, meter.threshold) rather than poll, register an event webhook — see webhooks.md.

Payload Retention: Recording Completed Acts

The record verb (POST /v1/record, POST /v1/record/batch) attests completed acts with hash commitments. Planisphere stores hash commitments only — retain your payload to re-prove WHAT was recorded. Archive the payload bytes (or a durable pointer) alongside the returned action_key; every record response repeats this warning in its payload_retention field. For period evidence: GET /tenant/exports/records?from=&to=&cursor= → POST /evidence-packets/seal-bundle/batch (body is {"action_keys": [...]}; POST /v1/record/batch by contrast takes a bare JSON array of record bodies) → GET /v1/records/{action_key}/inclusion-proof (records anchor on the hourly roll-up epoch; a just-sealed record returns 409 with an estimated_next_epoch_at hint until the next epoch).