Approvals

Use an approval when your agent wants to take an action that needs a human’s sign-off — issuing a refund, releasing a payout, sending an outbound email, or any destructive change to a system of record. The agent describes the action; a human approves, rejects, or edits it; the agent reads the decision back and acts.

The flow

An approval is a request you create on a task, then poll for the result. A common pattern is to gate only the actions that cross a policy threshold — the agent handles the routine cases, and humans see only the ones that need them.

1import time
2import uuid
3
4from pumpup import PumpUp, ApprovalRecommendation, Outcome
5
6client = PumpUp()
7
8def release_payout(task_id: str, claim_id: str, amount_usd: int):
9 if amount_usd <= 1000:
10 return pay(claim_id, amount_usd) # below threshold, the agent acts on its own
11
12 request = client.approvals.create(
13 idempotency_key=str(uuid.uuid4()),
14 project_name="claims",
15 task_id=task_id,
16 summary=f"Release ${amount_usd:,} payout on claim {claim_id}",
17 key_value_context={"Claim": claim_id, "Amount": f"${amount_usd:,}"},
18 recommendation=ApprovalRecommendation(
19 outcome=Outcome(type="APPROVE"),
20 confidence=0.91,
21 rationale="Damage matches the reported cause; estimate within policy limits.",
22 ),
23 )
24
25 while True:
26 result = client.approvals.get_result(id=request.event_id)
27 if result is not None:
28 break
29 time.sleep(2)
30
31 if result.outcome.type == "APPROVE":
32 pay(claim_id, amount_usd)
33 elif result.outcome.type == "EDIT_AND_APPROVE":
34 pay(claim_id, parse_amount(result.outcome.note)) # the note describes the edit

What you send

FieldRequiredDescription
summaryyesShort markdown describing the action.
key_value_contextnoA flat string→string map shown to the reviewer; the item view sorts by key.
recommendationnoThe agent’s lean: an outcome bid, a confidence (0–1, a UI cue), and a short rationale.
attachmentsnoUpload ids of files already on the task to render with the request.

What the reviewer decides

The reviewer picks one outcome, which comes back on result.outcome.type:

outcome.typeMeaning
APPROVEProceed as proposed.
EDIT_AND_APPROVEProceed, but with the change described in outcome.note.
REJECTDon’t proceed; outcome.reason_code may carry a coded reason.
ESCALATESend up the chain; outcome.note explains.
REQUEST_MORE_INFOSend a fresh request with more context.

There’s no structured diff for an edit — the reviewer describes their change in outcome.note, and the agent reads it and acts (or re-requests if it’s ambiguous).

The result

get_result returns None while pending, and once decided:

FieldDescription
outcome{ type, note?, reason_code? } — the decision.
decided_byThe reviewer’s user id.
decided_atWhen they decided.
authority_snapshotThe decider’s authority context, snapshotted onto the decision.
recommendation_snapshotThe recommendation you sent, copied in so the decision is self-contained.

A task holds one open request at a time — creating a second approval or elicitation while one is still pending returns a 409. Wait for the result, or open a separate task.