Client SDKs¶
Official thin clients for the Planisphere compliant-AI 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. The published 0.1.0 clients cover the gate, review and verification methods below. For completed-event recording, use the HTTP quickstart or a supported connection helper. The record and buffered-client methods in the 0.2.0 source are not yet available from those registries.
Python¶
pip install planisphere
from planisphere_sdk import Planisphere, PlanisphereNeedsReview, PlanisphereBlocked
ps = Planisphere(api_key="ps_live_...") # or ps_test_ for a free sandbox key
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_..."); // or a free ps_test_ sandbox key
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.verifyandverify_kit(verifyKit) — check a receipt, or fetch the offline verification recipe.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 signalsPlanisphereBlocked/PlanisphereNeedsReview(both carry.decision).
Sandbox¶
Create a free workspace, verify your email, and create a ps_test_
key in the console's Keys tab. No card is required. Sandbox
receipts are signed with a non-production key (dev_key: true) so they can never
be mistaken for production evidence. Upgrade the same verified workspace from
Billing; existing records retain their original signatures.
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).