Stripe Restricted Keys

Stripe restricted API key permissions: the complete reference for AI agents

A full breakdown of Stripe's permission scope system — every resource category, what Read vs. Write actually unlocks, the minimum permission set each agent role needs, and why scope alone doesn't stop a runaway agent from draining your account.

When you open the Stripe Dashboard and create a Restricted Key for an AI agent, you're confronted with approximately 60 resource toggles — each with three options: None, Read, or Write. The first time you see this form, the temptation is to check "Write" on everything to make sure the agent doesn't run into 403 errors. That approach defeats the purpose of using a restricted key at all.

This post is a reference for engineers who want to do it right. It covers what each permission level actually means, maps out the major resource categories with their risk profiles, gives you minimum permission sets for five agent archetypes, and explains the one gap that Stripe's permission system by design cannot close — the spend volume problem.

If you're new to Stripe API keys with restricted access and want a conceptual introduction before the reference, start there first. For concrete examples with CLI commands for five specific agent use cases, see our Stripe Restricted API key examples post. This post is the technical reference that sits between those two.

The three permission levels

Every resource on a Stripe Restricted Key can be set to one of three levels:

One Stripe quirk: some resources are Write-only from the key's perspective. Tokens is the classic example — you can grant the ability to create tokens but there's no read access to raw token data (for PCI reasons). Keep this in mind when you notice the form doesn't offer Read for certain resources.

Permission categories and risk profiles

The ~60 toggles break into logical clusters. Here's how to think about each cluster for an AI agent:

Core payments (high risk)

ResourceReadWriteAgent risk if Write granted
ChargesLowHighAgent can create charges on any stored payment method
Payment IntentsLowHighAgent can create and confirm payments; retry loops are expensive
RefundsLowHighAgent can issue unlimited refunds; no per-agent daily cap
Payment MethodsLowMediumAgent can attach/detach cards; misuse leads to unauthorized charges later
Setup IntentsLowMediumAgent can set up future charges without immediate payment
TokensN/AMediumWrite-only; agent creates tokenized card data (PCI boundary)

For most agents, you want Payment Intents and Charges at None unless the agent's explicit job is to initiate payments. Read is fine for agents that need to look up transaction history. Write on either should have a human-approval gate or a proxy-layer spend cap in front of it.

Customer data (medium risk)

ResourceReadWriteNotes
CustomersLowMediumWrite lets agent create/update customer records and default payment methods
Payment SourcesLowHighWrite lets agent add/remove cards; risk similar to Payment Methods Write
IdentityLowMediumStripe Identity verification sessions; Write creates new verification flows

Billing & subscriptions (medium risk)

ResourceReadWriteNotes
SubscriptionsLowHighWrite lets agent cancel, upgrade, or create subscriptions; revenue impact is direct
InvoicesLowMediumWrite lets agent void invoices or mark paid; Read is safe for billing agents
Invoice ItemsLowMediumWrite adds/removes line items on upcoming invoices
Subscription SchedulesLowMediumWrite lets agent modify future phase changes
PlansLowLowLegacy API for subscriptions; Read is generally all you need
PricesLowLowWrite creates new price points; rarely needed for agent access
ProductsLowLowProduct catalog; Write creates/modifies products, low direct financial risk
CouponsLowMediumWrite lets agent create discount codes; revenue impact if misused
Promotion CodesLowMediumWrite creates redeemable promo codes; same risk as Coupons
Tax RatesLowNone neededBilling agents don't need to create or modify tax rates

Connect / platform (high risk)

ResourceReadWriteNotes
AccountsLowHighWrite creates/modifies connected accounts; very rarely agent-appropriate
TransfersLowHighWrite sends money to connected accounts; highest financial risk of any permission
PayoutsLowHighWrite creates payouts to bank accounts; never grant unless agent explicitly manages payouts
Application FeesLowNone neededPlatform-level fee management; agents shouldn't need Write here

For most agents, the entire Connect cluster should be None. These permissions move money out of your platform to third parties. An agent that accidentally or maliciously has Transfers Write can drain your Stripe balance to connected accounts.

Operations & observability (low risk)

ResourceReadWriteNotes
BalanceLowN/ARead-only; safe to grant for monitoring agents
EventsLowN/ARead-only; all webhook event history
FilesLowLowWrite uploads files (e.g. dispute evidence); safe for dispute-handling agents
Webhook EndpointsLowMediumWrite lets agent create/modify webhook listeners; keep at None for most agents
ReportingLowN/ARead-only financial reports; safe for analytics agents
DisputesLowLowWrite submits dispute evidence; appropriate for customer-support agents

Checkout & other products (situational)

ResourceTypical agent need
Checkout SessionsWrite if agent creates payment links or hosted checkout flows; Read for analytics
Payment LinksWrite if agent creates shareable payment links; None otherwise
QuotesWrite for sales agents generating pricing quotes; None otherwise
TerminalNone for all cloud-based agents (in-person payments only)
RadarRead if agent needs fraud data; Write for custom rule management (rare)
ReviewsRead if agent monitors fraud reviews; Write to approve/refund (risky)

Minimum permission sets by agent role

Here are the tightest viable permission sets for the five agent archetypes we see most often. These pair with the detailed examples post which shows the exact CLI commands and gap analysis for each.

Support refund agent

Reads charge history, creates refunds. No payment initiation, no subscription access.

charges:read, customers:read, payment_intents:read, refunds:write

Billing & collections agent

Monitors invoice status, retries failed payments, reads subscription state. Does not create or cancel subscriptions.

customers:read, invoices:read, payment_intents:write, subscriptions:read, balance:read
Why payment_intents:write here? Retrying a failed payment requires confirming a PaymentIntent. If your agent only monitors and alerts (no automatic retry), use payment_intents:read instead.

Subscription management agent

Can upgrade, downgrade, or cancel subscriptions on customer request. Needs broader billing access.

customers:read, invoices:read, prices:read, products:read, subscriptions:write, subscription_schedules:write

Analytics & reporting agent

Reads transaction history, customer data, and revenue metrics for dashboards and reports. No write access anywhere.

balance:read, charges:read, customers:read, events:read, invoices:read, payment_intents:read, reporting:read, subscriptions:read

Dispute-handling agent

Monitors new disputes, gathers evidence, and submits responses. Reads charges and customers for context.

charges:read, customers:read, disputes:write, files:write

For all five, the Create Key CLI command follows the same pattern. See the single-example walkthrough for the full command syntax and how to use Stripe's API directly if you prefer not to use the CLI.

The principle of least privilege, applied

Least privilege for Stripe keys means: grant the minimum access the agent needs to complete its primary function on its worst day. Not the minimum access for the happy path — the minimum for a retry storm or a logic error.

Three questions to run for each resource before granting Write:

  1. Does the agent's function require creating or modifying this object? If it only needs to look things up, use Read.
  2. What's the worst case if the agent calls this endpoint in a tight loop? For Refunds Write: unbounded money out. For Products Write: catalog corruption, not financial loss. Weight the risk accordingly.
  3. Is there a downstream consequence I'm not thinking about? Granting subscriptions:write means the agent can cancel subscriptions. If your retry logic has a bug and runs cancel → re-subscribe → cancel in a loop, you've churned the customer and generated proration credits you didn't intend.

A useful heuristic: start with Read everywhere, run the agent against a test account, note which calls fail with 403, and only grant Write on the specific resources that fail. Never pre-grant Write "just in case."

What Stripe permissions cannot protect you from

Here's the uncomfortable truth about Stripe restricted key permissions: they are endpoint-level guards, not volume guards. A key with refunds:write can create one refund or ten thousand refunds. Stripe has account-level rate limits (typically 100 req/s), but at $50 per average refund, 100 requests per second is $5,000 per second in potential outbound. The permission system has no concept of "this key is only allowed to issue $500 in refunds today."

The three gaps that come up most in practice:

These gaps are not criticism of Stripe — the permission system solves the problem it was designed to solve (endpoint-level access control). The gaps are where a proxy layer like Keybrake operates: enforcing daily USD caps per vendor, scoping agent keys to a specific merchant or customer set, and blocking specific parameter values at the proxy level before the request ever reaches Stripe.

Layering Stripe permissions with a proxy policy

The pattern that closes all three gaps is a two-layer key architecture:

  1. Stripe Restricted Key — set to the minimum endpoint permissions the agent needs. This is your hard outer wall: the agent simply cannot call endpoints it doesn't have permission for.
  2. Proxy-layer vault key — a Keybrake vault key that the agent actually uses. The proxy enforces the policy (spend cap, customer scope, parameter allowlist) before forwarding to Stripe using the restricted key. If the policy is violated, the request is rejected before it touches Stripe.

An example: a refund agent gets a vault key with policy {vendor: "stripe", daily_usd_cap: 500, allowed_endpoints: ["/v1/refunds", "/v1/charges/*", "/v1/customers/*", "/v1/payment_intents/*"], expires_at: "+30d"}. The underlying Stripe key has charges:read, customers:read, payment_intents:read, refunds:write. The Stripe permission blocks payment creation at the API level; the proxy cap blocks refund volume at the business-policy level. Two different threat models, covered by two different controls.

The key question when scoping an agent: "If this agent's logic has a bug and it retries in a loop, how much damage can it do before I notice?" Stripe permissions constrain the shape of the damage (which endpoints). The spend cap constrains the scale of the damage (how many dollars). Both are necessary.

Quick reference: creating restricted keys via CLI

The Stripe CLI is the fastest way to create restricted keys with precise permissions. The general pattern:

stripe restricted_keys create \
  --name "agent-{role}-{YYYYMM}" \
  --permissions {resource}:{level},{resource}:{level}

Permission level values are read and write (not none — omit a resource entirely to leave it at None). Resource names use snake_case: payment_intents, subscription_schedules, webhook_endpoints.

# Analytics agent (read-only)
stripe restricted_keys create \
  --name "agent-analytics-$(date +%Y%m)" \
  --permissions balance:read,charges:read,customers:read,\
events:read,invoices:read,payment_intents:read,reporting:read,\
subscriptions:read

# Support refund agent
stripe restricted_keys create \
  --name "agent-support-refunds-$(date +%Y%m)" \
  --permissions charges:read,customers:read,payment_intents:read,refunds:write

# Dispute agent
stripe restricted_keys create \
  --name "agent-disputes-$(date +%Y%m)" \
  --permissions charges:read,customers:read,disputes:write,files:write

Name keys after their role and the month they were created. When you audit your API logs three months later trying to figure out what agent made a specific set of calls, the key name is your first signal. The Stripe Developers dashboard groups API calls by key, so a descriptive name makes forensics significantly faster.

Rotate keys monthly. Even if a restricted key has minimal permissions, rotation limits the window of exposure if a key leaks via logs, environment variable exposure, or a compromised deployment. An expired key from a month ago can't be used against you; a key you've never rotated is a liability that grows over time.

Checklist: before you deploy an agent with Stripe access

The permission system is the first line of defense. Answering these questions before deployment is the second. A proxy-layer cap is the third. None of them are sufficient alone — together they cover the threat models that actually matter when you give an autonomous agent access to your Stripe account.

Stop the next runaway agent before it costs you

Keybrake wraps your Stripe (and Twilio, Resend) keys with a proxy that enforces per-agent spend caps, customer scopes, and an audit log of every call — before anything reaches the vendor. Works alongside your Stripe restricted key permissions.