Skip to main content
Repo copy of this guide: docs/connectors/CONNECTING_AN_AGENT.md, kept in sync with this page. Covers the caller/agent side only. For what happens after APPROVED (Execution Gateway → connector → the real business system), see Add a connector and docs/connectors/PAYTM_CONNECTOR.md (repo root).

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.0.0/policy.json — don’t guess field names from a description. 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: docs/operations/2026-09-15-kms-migration-troubleshooting-guide.md.
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. 7. Send it, handle the response — see the complete reference table below. 8. Before claiming real execution, confirm a connector is actually registered for your capability on this deployment. docs/site/guides/live-api-and-demos.mdx documents that the general-purpose demo deployment historically had no connector registered at all. “Got APPROVED” and “the action executed” are two separately-verifiable claims — never conflate them. 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 cited to the exact source producing it:

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.
  • Claiming execution from APPROVED alone, without confirming connector registration.
  • 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 500 always means your request was wrong — it’s deliberately ambiguous by design.

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: docs/operations/2026-09-15-kms-migration-troubleshooting-guide.md.

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.