The short answer
Never give an AI agent a Stripe secret key (sk_...). A secret key has unrestricted permissions on all Stripe APIs, and Stripe no longer recommends them for new use cases.1 Give the agent a restricted API key (rk_...) with only the permissions it needs, and when you create it, tag it as authorising agent access to your account. Stripe calls this the recommended way to give autonomous agents access: agent-tagged keys are automatically subject to approval rules, and by default a refund, a subscription cancellation, a payout, an outbound payment or transfer, or a currency conversion they start waits for a designated reviewer.13
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
Secret key, restricted key, agent key
| Key | What it can do | For agents? |
|---|---|---|
Secret sk_... |
Everything, on every Stripe API | No: Stripe recommends moving secret key usage to restricted keys1 |
Restricted rk_... |
Only the resources you set to Read or Write; everything else is None by default2 | Yes, as the base |
| Restricted, agent-tagged | Same permissions as a restricted key, plus automatic approval rules for sensitive actions1 | Yes, Stripe’s recommended setup |
The agent tag doesn’t change what the key can authenticate to. It changes governance: sensitive actions it starts become approval requests instead of happening immediately.1
Permissions for a refund agent
Stripe’s method for setting permissions is empirical: start in a sandbox with a restricted key, run the integration, read the key’s request logs, and map each successful call to a permission. GET calls need Read; POST and DELETE calls need Write; Write includes Read. If a key lacks a permission, Stripe returns an invalid request error whose message names the permission to add.2
For an agent that looks up a customer’s payment and issues a refund, a starting point to test in a sandbox might be:
| Resource | Permission | Why |
|---|---|---|
| Refunds | Write | To create the refund |
| Payment Intents | Read | To find the payment being refunded |
| Charges | Read | Older integrations refund by charge |
| Customers | Read | To confirm whose payment it is |
| Everything else | None | Payouts, payment methods, products, Connect, Billing |
Then run the agent’s whole flow in the sandbox and trim anything the request logs show it never used. One restricted key per service or use case is Stripe’s advice, so a compromised agent key can’t touch what the billing service does.2
Approval rules: what waits for a person
Stripe keeps default approval rules for these actions by agent-tagged keys: refund created, subscription cancelled, outbound payment, outbound transfer, payout, and currency conversion.3 When one triggers:
- The action is interrupted and an approval request is created.
- A designated reviewer approves or denies it in the Dashboard. A user can’t approve their own request.
- Approved actions complete automatically; denied ones are discarded with no change.
- Requests not approved within 14 days expire.3
You can edit the default rules’ conditions and reviewers. Useful conditions include an amount threshold (approve refunds above a limit only), an actor condition (only agent-tagged keys), and a rate limit (approve when there are more than N requests in a window). A rule can also block an action outright instead of pausing it.3
On a single-person Stripe account, two-party approval can only be saved with the actor set to agent-tagged keys, because the agent key counts as an actor separate from the administrator.3 That’s the setup a solo founder wants anyway.
Handling approval_required in your agent
When an agent-tagged key hits a rule, Stripe returns an approval_required error and submits the approval request itself.3 Your agent code has to treat that as “pending,” not “failed”:
- Don’t retry. A retry creates a second request for the same refund.
- Tell the user plainly: “The refund is waiting for approval,” not “Done.”
- Attach a reason. Stripe lets you update the approval request with a justification, such as the support ticket the refund came from.3
- Listen for the outcome. Events such as
v2.core.approval_request.approved,.rejected,.expired,.succeededand.failedtell you what happened.3 Onlysucceededmeans money moved.
The last point matters for any agent that reports its own work. “Approved” and “completed” are different events; an approved action can still fail when it runs.
Lock the key down
Permissions limit what the key can do. These limit who can use it:1
- Access policies. Restrict the key to known IP addresses or CIDR ranges, or with an advanced policy by network (ASN), country and blocked sources such as Tor exit nodes. Stripe blocks other requests and notifies you. Stripe recommends policies on all live keys.
- A secrets vault, not a file. Stripe says not to put keys in source code or in configuration files checked into version control. For agents, that includes
.envfiles the agent can read; our post on API keys in .env files covers why. - Rotation. Rotating revokes the key and issues a replacement; in the Dashboard both keys work for up to 7 days so you can migrate without downtime.
- Logs. Each key has request logs in Workbench. Check them weekly for calls you didn’t expect.
What this doesn’t cover
- Actions outside the default rules. A key with Write on Customers can change customer details without approval unless you add a rule; approvals are supported for a specific list of actions.3
- Whether the refund was right. The reviewer sees the request; deciding it’s correct is their job. Give them the context: the ticket, the order, the reason.
- Other tools in the session. If the same agent can send email or post to Slack, the approval on refunds doesn’t cover those. Human-in-the-loop approval explains the pattern for tool calls generally.
A checklist
- No
sk_key anywhere the agent can read. - A restricted key, tagged for agent access, one per agent or service.
- Permissions set from sandbox request logs; everything unused is None.
- Default approval rules kept, with reviewers who’ll answer within a day.
- Amount thresholds or rate limits added where useful.
- The agent treats
approval_requiredas pending and doesn’t retry. - An access policy on the live key.
- Request logs reviewed weekly.
Our guide to Stripe refunds shows the same approval idea applied at the tool-call level, in front of any key. To see what the agents configured on your machine can change, paste the config into the check page or run npx deedglass scan (how the grade works); to try the checks in your browser first, open the playground.
Written with AI assistance and checked against our claims register.