A Slack support agent tries to refund a customer. Kynara requires a manager to approve it.
Press play. Watch an AI support agent handle a refund in Slack, hit Kynara's policy check, pause for human approval on the money-moving step — and land every decision in a tamper-evident audit log. You are the manager: approve or reject when prompted.
Ready.
Slack · #support
Press Play to start the scenario…
Kynara · Decision engine
Waiting for a tool call to authorize…
Tamper-evident audit log · SHA-256 hash-chained
No decisions recorded yet.
What just happened
The agent had permission to read the account and draft a reply, but the refund is a money-moving action. A Kynara policy says any refund over $50 returns require_approval, so the agent paused instead of paying out. A human manager approved, the refund executed, and the whole chain — request, decision, approver, execution — is recorded and verifiable. A prompt injection in the customer message can't change that, because the decision is made outside the model.
The policy & the code
// Refunds over $50 need a manager. Effect: require_approval.
{
"name": "Refunds over $50 need manager approval",
"effect": "require_approval",
"priority": 100,
"actions": ["payments.refund.issue"],
"condition": {
"op": "gt",
"args": ["ctx.resource.attrs.amount_cents", 5000]
}
}
from kynara_sdk import Kynara, ApprovalRequired
k = Kynara(api_key=KEY, agent_id="slack-support-agent",
user_id="dana_r", fail_closed=True)
decision = k.check(
action="payments.refund.issue",
resource={"type": "payment", "id": "pay_8842",
"attrs": {"amount_cents": 8900, "customer": "cus_dana"}},
context={"channel": "support", "reason": "duplicate charge"},
)
if decision.effect == "require_approval":
raise ApprovalRequired(decision.approval_id) # agent pauses here
# ...on approval, the refund actually runs
stripe.Refund.create(payment_intent="pay_8842", amount=8900)
Runnable version (with approval polling) is in the repo at examples/refund-approval-demo/.