Skip to main content
Covers the caller (agent) side. The repository’s docs/connectors/CONNECTING_AN_AGENT.md points here. For what happens after approval (gateway, connector, the real business system), see Connect any external system, the Connector Development Guide and docs/connectors/PAYTM_CONNECTOR.md.

The mental model

The agent proposes an intent. Parmana decides whether it’s authorized. Only Parmana’s decision can unlock execution. If your integration ever lets the agent set a value that determines the outcome , an approval flag, a fraud-check result, a policy name, the model is broken, even if it “works.”

What you need, and why

Step by step

1. Read the policy file directly. cat policies/customer-refund/1.2.0/policy.json; don’t guess field names from a description. Ask the server which version is in effect: GET /policies/in-effect?capability=paytm:refund. 2. Pick the exact capability string. Case- and character-exact. This single detail is the most common integration failure in practice. 3. Mint a scoped API key:
Use SERVICE, never "AGENT", that value doesn’t exist in AuthorityType. Never grant "*" to a single-purpose agent; /callers/me’s unrestrictedCapabilities is literally allowedCapabilities.includes("*").
If you’re the deployment operator adding this key (not just the agent developer): PARMANA_API_KEYS is one environment variable holding a JSON array. Two real mistakes were made hand-editing a live deployment’s value in a hosting dashboard: pasting the new entry as the entire value instead of appending it to the array (every caller gets a 500 until fixed, the server fails closed on malformed JSON), and losing existing entries by replacing rather than appending. Always paste the complete array, every existing entry plus the new one. Full account: the 2026-09-15 KMS migration troubleshooting guide (in git history).
4. Verify the key before writing agent code:
If this fails, fix authentication first, nothing about your agent’s request shape is relevant yet. 5. Wire up real trusted-signal sources for every field in the policy’s signalsSchema. Not a placeholder to fix later, from day one. 6. Build the request:
This example was missing metadata until 2026-09-14, found while running End-to-end: agent → Parmana → Paytm against a real deployment. Omitting it fails with {"error":"metadata.businessTransactionId must match businessTransactionId."} (400), before policy is ever evaluated. It’s now included below.
policy.name/policy.version is never inferred from intent.action: name it explicitly, or a caller could pair a real capability with an unrelated policy. Under customer-refund 1.2.0 every refund needs a signed manager approval (G-75); without one the request is refused with 403 POLICY_DENIED, whatever your agent declares about eligibility and fraud. 7. Send it, handle the response, see the complete reference table below. 8. Confirm a connector is registered for your capability on this deployment. A 200 means the action was released and executed and its Trust Record signed; with no connector the answer is 503 CONNECTOR_NOT_REGISTERED and nothing ran. To practise end to end with nothing installed, use the public sandbox’s sandbox:receipt (Playground). To connect your own system without code, see Connect any external system. 9. Verify independently: GET /refusal/:id + POST /refusal/verify for a rejection, GET /trust-records/:id (only once a connector is wired) for an execution, or fully offline with verifyExecutionTrustRecordOffline.

Complete response reference

Every row is what the server returns today (2026-10-02); the Error catalog has every code.

Common mistakes

  • Capability string mismatch between intent.action and your key’s allowedCapabilities.
  • authorityType: "AGENT", invalid; use "SERVICE".
  • A signal inferred from the customer’s words instead of an independent business system.
  • Treating POLICY_DENIED as a bug instead of a correct decision.
  • Treating a timeout as a failure and sending the action again under a new id.
  • Granting "*" “to get it working” and never narrowing it.
  • Hand-editing PARMANA_API_KEYS by pasting a single entry instead of the complete array.
  • Assuming a bare 500 means your request was wrong: ask for the server log first.

Reference implementation

pavancharak/parmana-phinite-agent is a real, working implementation of every step above. Two bugs were found and fixed in it: the exact CAPABILITY_NOT_ALLOWED mistake from the table above ("refund" instead of "paytm:refund"), and error handling that crashed instead of resolving unrecognized failures to an unresolved client-side state. See that repository’s README for the full writeup. Second round, entirely on Parmana’s own side (2026-09-15/16): after those agent-side fixes, this same integration hit a sequence of purely Parmana-operator issues onboarding as a new caller on a freshly KMS-migrated deployment: no PARMANA_API_KEYS entry at all (401) → a malformed hand-edited entry (500 for every caller) → no allowedPrincipalIds grant for the asserted principal (403) → a genuine Parmana-side bug where the gateway’s signing and verification paths silently used different keys after a KMS migration (500, unrelated to the request itself , examples/tutorials/114-signing-verification-key-agreement/ reproduces it). None of these were agent bugs. Full account: the 2026-09-15 KMS migration troubleshooting guide (in git history).

Next

Add a connector

What happens after APPROVED: Execution Gateway, connector dispatch, execution evidence.

Live API and Demos

Call the real, deployed Parmana API directly and see what’s and isn’t wired on it today.