Skip to main content
Every endpoint, error, and worked example below has been run against the live deployment. Base URL: https://parmana-api-real.vercel.app. Repo copy of this guide: LIVE-API-GUIDE.md (repo root).

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. paytm:refund is a real, wired connector on this deployment: PAYTM_CONNECTOR_URL/PAYTM_CONNECTOR_SHARED_SECRET point at a real, separately deployed parmana-paytm-agent service, which itself calls Paytm’s staging API. An approved paytm:refund request reaches Paytm’s real staging API and returns a real result, with a full cross-service audit trail correlated by businessTransactionId. Full runbook: End-to-end: agent → Parmana → Paytm. Isn’t (still true for HubSpot/GitHub): no HubSpot token, no GitHub App credentials configured, and it isn’t running in test mode either. This mirrors a real, documented finding in this codebase (see Limitations and the vendor-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 for hubspot-deal-update/github-pr-approval/etc. reaches Policy Engine and gets signed, then fails with a 503 (code CONNECTOR_NOT_REGISTERED) at the dispatch stage, 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 regardless of capability. Plan demos around that: “the system correctly declines” is a complete, real demo for any capability; “money/data actually moves” is real and demonstrable specifically for paytm:refund as of this correction, not yet for HubSpot/GitHub without adding real credentials.

Authentication

Bearer token in the Authorization 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:
This prints the raw key once and a config entry to add to the deployment’s caller-key list, then requires a redeploy to take effect. See Authentication for the full caller-auth model, and 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

Hard requirements, all fail-closed with a clear 400/403 if wrong:
  • businessTransactionId must be a real UUID, not a slug.
  • authority.authorityType must be one of USER, ROLE, SERVICE, ORGANIZATION. An autonomous agent maps to SERVICE ("AGENT" is not a valid value, a real mistake made and caught while building this deployment).
  • policy.name/policy.version must match a real, deployed policy, the caller names the policy explicitly, it is not inferred from intent.action.
  • Every fact a policy’s rules reference must appear in signals. A fact declared as boundSignals is additionally cross-checked against the real intent field 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.

Connect an external agent

How an AI agent authenticates, sends a governed request, and handles APPROVED/REJECTED — the real parmana-phinite-agent integration as the worked example.