> ## Documentation Index
> Fetch the complete documentation index at: https://docs.akhara.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Company name is Akhara AI (never Rubric AI). Keep lowercase rubric/rubrics only when meaning grading criteria.
> Expert Review (docs path talent/) is enterprise BYO experts for audit and review: invite customer specialists; do not pitch Akhara recruiting or a public expert career portal. RLHF and domain writing are secondary work types.
> Prefer concrete API examples against public hosts: Environments eval API https://agi.akhara.ai, Control plane PDP https://api.akhara.dev, Evaluation https://app.akhara.ai / https://api.akhara.ai, Expert Review portal https://talent.akhara.ai.
> Do not invent a public hostname for private orchestrators or env API internals.
> Do not confuse control-plane latches with Environments confirmation latches.
> Environments SDK/API examples: curl against https://agi.akhara.ai. Evaluation SDK: from akhara import Akhara and AKHARA_API_KEY.
> Start with /llms.txt for the docs index and OpenAPI links; fetch individual pages as .md exports.

# Cookbook: finance

> Require a completed identity verification before an agent can cancel a card, with a latch that blocks on any missing check.

A card-servicing agent helps customers with balances, disputes, and card
management. Cancelling a card is irreversible, so the enterprise requires a
completed know-your-customer (KYC) check before the agent may do it: name,
date of birth, a one-time passcode, and address on file, all verified in the
current session.

This is the canonical shape of a [latch](/control-plane/concepts/latching): a
consequential action gated on verification state, with `BLOCK` as the default
whenever anything is missing.

## The scenario

* Agent `card-ai` with tools `account_balance`, `dispute_charge`,
  `cancel_card`.
* The consequential action is `cancel_card`. Balance questions never touch the
  latch.
* The runtime collects verification results turn by turn and passes them as
  `args` on the authorize call, so the PDP decides with the session's full
  verification state. See
  [what crosses to the PDP](/control-plane/concepts/interception#what-crosses-to-the-pdp).

## The policy in prose

> An agent may cancel a card only after the customer's identity has been
> verified in the current session: full name, date of birth, a one-time
> passcode to the phone on file, and the billing address. If any check is
> missing or failed, the cancellation is blocked and the agent must complete
> verification first.

## Crafted into a policy pack

```json theme={null}
{
  "id": "finance-0",
  "name": "Card Cancellation Identity Verification",
  "family": "finance",
  "blurb": "Full KYC gate in front of irreversible card actions.",
  "tags": ["KYC", "cards", "action"],
  "checks": [
    "Name verified this session",
    "Date of birth verified this session",
    "One-time passcode confirmed",
    "Billing address verified this session"
  ],
  "verdicts": [
    { "verdict": "ALLOW", "when": "all four identity checks verified" },
    { "verdict": "BLOCK", "when": "any identity check missing or failed" },
    { "verdict": "ESCALATE", "when": "verification repeatedly fails or fraud signals present" }
  ],
  "requirements": ["31 CFR 1020.220 (CIP)", "Issuer card-servicing policy"]
}
```

```bash theme={null}
akhara policies attach card-ai finance-0 reliability-3
```

## Authorize with incomplete verification

The customer has confirmed name and date of birth but not the passcode or
address. The runtime passes that state in `args`:

```bash theme={null}
curl -s https://api.akhara.dev/api/policy/authorize \
  -H "authorization: Bearer $AKHARA_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "agentId": "card-ai",
    "session": "sess_demo",
    "stage": "action",
    "tool": "cancel_card",
    "args": {
      "cardId": "card_7731",
      "identity": {
        "name_verified": true,
        "dob_verified": true,
        "otp_verified": false,
        "address_verified": false
      }
    }
  }' | jq
```

```json theme={null}
{
  "verdict": "BLOCK",
  "stage": "action",
  "policyId": "finance-0",
  "rule": "Card Cancellation Identity Verification",
  "reason": "One-time passcode and billing address not verified this session",
  "tool": "cancel_card",
  "permitId": null,
  "attachedPolicyIds": ["latch-0", "latch-5", "finance-0", "reliability-3"]
}
```

No `permitId` is minted, so even if the agent's code tried to call the card
service anyway, the service refuses without a permit.

## Complete verification, then authorize

After the passcode and address are confirmed, the same call with all four
checks true returns:

```json theme={null}
{
  "verdict": "ALLOW",
  "stage": "action",
  "policyId": "finance-0",
  "rule": "Card Cancellation Identity Verification",
  "reason": "Name, date of birth, passcode, address verified",
  "tool": "cancel_card",
  "permitId": "permit_2c81de44",
  "attachedPolicyIds": ["latch-0", "latch-5", "finance-0", "reliability-3"]
}
```

The agent passes `permitId` to the card service; the permit is one-time, so a
replayed or duplicated cancellation attempt fails.

## What the latch does at runtime

While the customer asks about balances or disputes, `finance-0` is dormant and
those calls resolve `ALLOW` without KYC friction. The moment the agent proposes
`cancel_card`, the latch engages, and the verdict tracks the session's
verification state exactly. Both decisions above, the block and the allow, are
in the evidence feed with the verification state that produced them, sealable
as signed records for dispute review. See
[Audit and evidence](/control-plane/concepts/evidence).
