The problem
An AI agent that can call a payment API, a CRM, or a vendor system needs a credential to do it. Give the agent that credential directly and the agent’s own (probabilistic, sometimes wrong) reasoning is the only thing standing between a user’s request and a real-world action.The solution
The agent proposes the action to Parmana as a Business Transaction. A named, versioned policy, not the agent, decides. Your code only calls the downstream system (or, in a real deployment, a registered Connector calls it on Parmana’s behalf) once Parmana returns an approvedExecutionTrustRecord.
client and createBusinessTransaction setup from
the quickstart.
Pattern 1: LangChain.js tool
Pattern 2: Vercel AI SDK tool calling
{ approved,... } object instead of a string works well here since
the model can reason over the fields directly in a follow-up turn.
Pattern 3: Express / Fastify endpoint
Putting the Parmana call behind your own endpoint keeps the agent’s tool-calling surface thin, the agent calls your API, your API calls Parmana:app.post(path, handler) for
fastify.post(path, async (request, reply) => {... }) and the body is identical.
Pattern 4: Async workflow with a webhook callback
For an agent whose action needs to run out-of-band (a long-running batch, a human-in-the-loop step) rather than inline in the conversation turn, submit the transaction and notify a webhook when the trust record lands, instead of blocking onawait:
client.execute() itself is a single request/response call, not a streaming one, this
pattern is about decoupling your workflow from the caller’s request/response cycle, not
about Parmana’s own API shape.
Real example: a CustomerServiceAgent class
Key guarantees
- The agent (LangChain.js, the Vercel AI SDK, or a hand-rolled loop) never sees the downstream connector credential, only a registered Connector does.
- A denial surfaces as data (
ExecutionRejectedError, or a{ approved: false }result), not a crash, the calling agent framework’s normal error/retry handling applies. - Every refund needs a signed manager approval for that order and amount; without one the
request is refused with
403 POLICY_DENIED(Human approval). - The policy version is explicit in every call (
policy: { name, version, schemaVersion }), and it must be the version in effect (GET /policies/in-effect), so an agent can’t silently drift onto a different policy between calls. - Every approved execution returns a signed
ExecutionTrustRecord, independently verifiable later withclient.verify()regardless of which pattern above produced it. signalsare checked againstboundSignalsbefore policy evaluation, so an agent can’t satisfy the policy’s signals while pointingtarget/parameterssomewhere else.
Next
TypeScript SDK in Production
Config, retries, audit logging, and a deployment checklist for the pattern
above.
Write your first policy
What
customer-refund@1.2.0 actually evaluates, and how to write your own.Connect an agent
The framework-agnostic version of this page’s four patterns.
End-to-end: agent → Parmana → Paytm
This exact
paytm:refund action, run against real, live infrastructure.