Skip to main content
When an agent sends a request that a policy authorizes only with a signed approval, such as a refund that needs a manager, Parmana refuses it and the agent must send a new request with the approval attached. Approval notifications tell the approver right away. Parmana sends a signed approval.needed event to a URL you choose, with exactly what the approver needs to sign.

When an event is sent

Parmana sends one event when all of these hold:
  1. The request was refused by the policy’s own rules, or because an attached approval did not verify.
  2. The policy declares approvalSignals.
  3. Evaluating the same policy, with every declared approval signal set to true, authorizes the request.
The third condition means an event only goes out when an approval would actually help. A refund refused for a failed fraud check, or above the policy’s maximum, sends nothing, because a manager’s signature would not change the outcome. Requests refused before the policy runs, such as a bad API key or a request whose signals do not match its own parameters, send nothing.

Set it up

1

Create an endpoint

Any HTTPS endpoint that accepts a JSON POST and answers 2xx within 3 seconds: a small function of your own, a Slack workflow webhook behind a relay, or an automation service.
2

Generate a secret

Store it where your endpoint can read it. You will verify every event with it.
3

Configure Parmana

Set both variables on the deployment, then redeploy:
With PARMANA_SECRETS_PROVIDER=aws-secrets-manager, APPROVAL_WEBHOOK_SECRET is the name or ARN of the secret instead of its value. Setting only one of the two stops the server at startup. The URL must be https outside NODE_ENV=test and development.
4

Send a test request

Send a request the policy refuses only for want of an approval, for example a refund with managerApproved: false and every other fact true. Your endpoint receives an event.

The event

string
required
Always approval.needed.
string
required
When the request was refused, ISO 8601 UTC.
string
required
The refused request. Its Refusal Record has the full decision.
string
required
The refusal decision.
string
required
The action that needs approval, such as paytm:refund. Sign with this as capability.
string
required
The request’s target.
string
required
The policy that refused it.
string
required
Its version.
string
The refusal reason from the policy.
string
The caller that sent the request, when known.
object[]
required
One entry per approval the policy declares.
The event carries only what the approver needs. Other request parameters and signals are not sent; look them up by businessTransactionId if you need them.

Verify the signature

Every event has two headers: Verify against the raw request body, before parsing it, compare in constant time, and refuse a timestamp more than 5 minutes old so a captured event cannot be replayed later.

From event to approval

The approver signs exactly what the event names:
The agent then sends a new request, with a new businessTransactionId, the approval signal set to true, and the approval in signals.approvalArtifact. See Human approval.
An event says a request is waiting. It is not an instruction to approve it. The approver decides, on their own machine, with their own key; your endpoint should never sign approvals automatically.

Delivery

Because delivery is best effort, the Refusal Records remain the complete list of waiting requests. For a daily sweep, see Review refused requests.

Test locally

Point the webhook at a local listener and run Parmana in development:
http is accepted only in development and test.

Reference

See also Environment variables.