[AVAILABLE]. Every endpoint, error, and worked example below was run against the
live deployment while writing this page, not written from the spec alone. Base URL:
https://parmana-api-real.vercel.app. Repo copy of this guide: LIVE-API-GUIDE.md
(repo root), this page and that file are kept in sync.Goal
Build a demo by calling a real, running Parmana deployment directly, no local setup, no mocked responses. This is the real, production@parmana/api code, not a sandbox or a
simplified illustration.
What this deployment is, and isn’t
Is: a real authorization engine. Submit a Business Transaction, it evaluates the named policy against your declared signals, produces a real, deterministic, Ed25519-signed decision (approve/reject), and persists it durably. Rejections complete end to end, signed, durable, retrievable. Genuinely useful for demoing policy authoring, signal binding, guardrails correctly declining a request, cryptographic proof of a decision, independent offline verification, and audit trails. Isn’t: a live payment/CRM/deployment system. No connector is registered on this deployment, no HubSpot token, no GitHub App credentials configured, and it isn’t running in test mode either. This is deliberate: it mirrors a real, documented finding in this codebase (see What Parmana does not claim and thevendor-payment policy’s own history) that a capability should not be wired to a connector
until its signals are independently verified, not merely caller-declared.
Concretely: an approved decision reaches Policy Engine and gets signed, then fails
with a 500 (No connector registered for capability '<name>') at the dispatch stage, for
every capability, including the ones with real connector code (HubSpot, GitHub), since
their credentials aren’t configured on this deployment. A denied decision never reaches
that stage (policy rejection happens before dispatch), so it always completes cleanly. Plan
demos around that: “the system correctly declines” is a complete, real demo on this
deployment; “money actually moves” is not, unless you add real connector credentials.
Authentication
Bearer token in theAuthorization header. Two keys are currently provisioned:
Raw key values are shown once in a terminal and never committed to the repo, only their
salted hashes live in the deployment’s environment configuration. To mint your own:
LIVE-API-GUIDE.md (repo root) for the exact commands.
Principal scoping is a separate check from capability scoping: a key with no explicit
principal grant may only assert authority.principalId equal to its own caller id.
Simplest path, set authority.principalId to "demo" in every transaction you submit
with the demo key.
The shape of a request
400/403 if wrong:
businessTransactionIdmust be a real UUID, not a slug.authority.authorityTypemust be one ofUSER,ROLE,SERVICE,ORGANIZATION. An autonomous agent maps toSERVICE("AGENT"is not a valid value, a real mistake made and caught while building this deployment).policy.name/policy.versionmust match a real, deployed policy, the caller names the policy explicitly, it is not inferred fromintent.action.- Every fact a policy’s rules reference must appear in
signals. A fact declared asboundSignalsis additionally cross-checked against the realintentfield it’s bound to, or the whole request is rejected before Policy Engine ever runs.
Available policies
Full signal schemas for every policy:
LIVE-API-GUIDE.md (repo root).
Writing a new policy
A policy is one JSON file:policies/<policyId>/<version>/policy.json. Four condition
shapes (leaf comparison, all, any, always), a fixed operator set (eq, neq, gt,
gte, lt, lte, between, in, not_in, contains, not_contains, contains_all,
contains_any, starts_with, ends_with, matches, exists, not_exists, is_true,
is_false, is_null, is_not_null, length_eq, length_gt, length_gte, length_lt,
length_lte, type_is), and one rule that’s easy to miss: every fact your rules
reference must appear in either boundSignals or unboundSignalReasons, or the policy
fails to load at all, no silent, unacknowledged gaps allowed.
The expense-reimbursement@1.0.0 policy above is a real, worked example of this, full
schema, the exact validation rule that would reject a badly-formed policy, and how to
deploy a new one (git add + vercel deploy --prod, since policies are baked into the
build) are all in LIVE-API-GUIDE.md (repo root), tested live while writing it: write,
validate, deploy, call, get a signed decision, independently verify.
Endpoints
Full table, every route, and copy-pasteable
curl examples: LIVE-API-GUIDE.md (repo
root). Machine-readable spec: GET /openapi.yaml or the REST API
reference.
Verifying a result independently
GET /trust-records/:id only returns a record for a capability with a registered
connector, none on this deployment. For a real, fetchable, signed artifact today, use the
Refusal Record: fetch it via GET /refusal/:id, then verify with zero further server
calls using verifyExecutionTrustRecordOffline from @parmana/crypto for an
ExecutionTrustRecord, or POST /refusal/verify (server-side, but still genuinely
cryptographic and unauthenticated) for a RefusalRecord. See Verify a trust record
independently for the fully offline path, and
examples/tutorials/107-offline-verification/ through 110-hybrid-signature-downgrade-protection/
for runnable, tested demonstrations of every scenario, including a hybrid (Ed25519 +
ML-DSA-65) record and a downgrade-attack proof.
Next
Write your first policy
A slower, more conceptual walkthrough of policy authoring than the reference above.
Verify a trust record independently
The fully offline verification path, in depth.