Production base URL:
https://parmana-api-real.vercel.app. Checked against
the code and the deployment on 2026-10-02.Goal
Call the real, running production deployment directly, no local setup, no mocked responses. It runs the same@parmana/api code as the sandbox, with real connectors and real
credentials, so it is open only to callers its operator has issued a key.
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
example-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 to Parmana to Paytm.
token, GitHub App credentials or Slack bot token is configured, and it isn’t running in test
mode either. An approved request for one of these answers 503 CONNECTOR_NOT_REGISTERED, which
is how to check it today. 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 request for hubspot:deal-update, github:pr-merge, slack:post-message
and the other HubSpot and GitHub actions is refused with a 503
(code CONNECTOR_NOT_REGISTERED) before release, and nothing runs, since their
credentials aren’t configured on this deployment. A capability registered as an external
connector is released to its own endpoint. 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 theAuthorization header. Production has no public or demo key: every
per caller, scoped to the capabilities it needs (for example paytm-refund-agent, allowed only
paytm:refund). To try requests without a key of your own, run a local server with the Quickstart.
Raw key values are shown once in a terminal and never committed to the repo; only their
hashes live in the deployment’s environment configuration. To mint a key for an agent, scoped to
its capabilities:
"*" to an agent. See
Authentication for the full caller auth model, and
Credentials: maker, checker and approver 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 your own caller id.
The shape of a request
400/403 if wrong:
- Every request needs a signed human approval in
signals.approvalArtifact, for this action and resource (and amount, where the policy names one), with the policy’s approval signal settrue.managerApproved: truewithout it is refused. See Human approval. 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
No AI agent action is authorized without a signed human approval, reads included. Every current policy needs one; the column on the right names the signal and what the approval must cover. Older versions that approved without a person (such asvendor-payment@2.0.0 or
github-pr-read@1.0.0) stay in the repository as history and are refused when they load. See
Human approval.
Full signal schemas for every policy: each policy file under
policies/<name>/<version>/policy.json (signalsSchema).
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.1.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 a new one
goes live (proposed and approved through policy governance, no deploy) are in
Write your first policy and
Policy lifecycle and approvals.
Endpoints
Machine-readable spec:
GET /openapi.yaml or the REST API
reference.
Verifying a result independently
An executed action has a Trust Record (GET /trust-records/:businessTransactionId); a refused one has a
Refusal Record (GET /refusal/:businessTransactionId). Verify a Trust Record with zero further server calls
using verifyExecutionTrustRecordOffline (TypeScript) or verify_execution_trust_record_offline
(Python) and the key from GET /keys/default, and a Refusal Record with POST /refusal/verify
(server side, but cryptographic and unauthenticated). 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, with the real parmana-phinite-agent integration as the
worked example.