Stripe Restricted Keys
What is my Stripe restricted API key?
A Restricted Key is a scope-limited Stripe secret key you create in the Dashboard. It prefixes with rk_, lives alongside your main Secret Key, and is the right tool when a long-lived secret needs a narrower set of permissions than the Secret Key grants.
TL;DR
Your Restricted Key is listed under Developers → API keys → Restricted keys in the Stripe Dashboard. It starts with rk_live_ (or rk_test_ in test mode). You created it yourself; Stripe does not create one by default. If you can't see a value, it's because Stripe shows the full key exactly once on creation — you'll need to reveal a fresh one or rotate.
Where to find it
- Sign in to the Stripe Dashboard.
- Click Developers in the left nav.
- Click API keys.
- Scroll past the Standard keys section to Restricted keys. If the section is empty, you have not created one yet.
Each row in that section shows a key name, the last-used timestamp, a permissions summary, and a Reveal test key or Reveal live key button. The reveal button only works in test mode or for a key you just created — live-mode Restricted Keys are hidden after initial creation.
What the rk_ prefix means
Stripe uses key prefixes to signal type at a glance. The common ones:
| Prefix | Kind | Scope |
|---|---|---|
pk_live_ / pk_test_ | Publishable key | Client-side, safe in browsers; limited to creating tokens/sources |
sk_live_ / sk_test_ | Secret key (Standard) | Full account access — never expose to a client |
rk_live_ / rk_test_ | Restricted key | Scoped subset of Secret-key permissions that you chose at creation |
whsec_ | Webhook signing secret | Verifies incoming webhook payloads |
How it differs from a Secret Key
Both a Secret Key and a Restricted Key are server-side credentials that can make real API calls. The differences are scope and lifecycle:
| Property | Secret Key | Restricted Key |
|---|---|---|
| Default permissions | All resources, Read + Write | Only what you tick at creation |
| Number allowed per account | One live, one test | Many |
| Visibility after creation | Always reveal-able in Dashboard | One-time reveal only (live mode) |
| Rotation | Dashboard Roll key button | Delete + recreate |
| Connect support | Full | Full (with caveats on Accounts scope) |
| Use case | Trusted internal backend with no sub-trust boundary | Third-party integrations, agents, subprocesses you don't fully trust |
A practical rule: if the code holding the key is something you'd let write your production database, a Secret Key is fine. If not — and an AI agent is not — you want a Restricted Key with the narrowest scope set that still lets the agent do its job.
Lifecycle rules that trip people up
- Reveal is one-time. When you create a Restricted Key in live mode, Stripe shows the full string exactly once. Close the tab and it's gone — you have to delete and recreate to get a new usable key.
- Deletion is soft. Deleted Restricted Keys linger in the Dashboard for roughly a week so you can see who had what. The key string stops working immediately though.
- Permission edits are live. If you tighten a Restricted Key's scope set after the fact, Stripe applies it instantly. In-flight calls that depended on the now-removed permission will return 401.
- No automatic expiry. Restricted Keys do not have a
expires_at. They live forever unless you delete them. - Last-used is approximate. The "Last used" column in the Dashboard updates on a few-minute delay, so recent traffic may not show yet.
Common confusions
"I can see the key name but not the value"
Correct — that's by design. In live mode, Restricted Keys are hidden after creation. Your application should already hold the key in its secret store. If it doesn't, delete this Restricted Key and create a new one, and copy the value on the reveal screen.
"The key used to work and now returns 401"
Three likely causes: someone tightened the scope set in the Dashboard; someone deleted and re-created under the same name; or you're sending a test-mode rk_test_ key against a live-mode resource (or vice versa). Check the account indicator in your logs — livemode: false on an expected-live call is a tell.
"I don't remember creating one"
It may have been created by a teammate. Check the Logs tab (Developers → Logs) for POST /v1/… calls with rk_…-prefixed keys; Stripe lists the key name on each entry. Or just ask your team — names are the clearest signal.
How Keybrake uses your Restricted Key
When you connect Stripe to Keybrake, you give us a single Restricted Key as the upstream credential. We hold that key (encrypted at rest) and issue per-agent vault_key_… credentials with additional policies layered on top: daily USD caps, customer scope, kill-switch. Your agents never see the real rk_live_…. If Keybrake's vault is ever breached, rotating the upstream Restricted Key locks us out of your account — the blast radius is contained. Full architecture on the homepage →
Related questions
Is a Restricted Key safe to commit to a private repo?
No. A Restricted Key is still a secret. Private repos get public by accident often enough that the rule is simple: no Stripe key of any type ever lives in a repo, public or private. Use your secret store.
Can I see who used a Restricted Key?
You can see that the key was used — Stripe's Logs tab shows the key name on each API call — but not who used it. If you need per-user attribution, you need to track it yourself, either in your code or via a proxy that tags each call with an agent identifier.
Does a Restricted Key count against my Stripe rate limit?
Yes. All keys on the same Stripe account share the account's rate limit. Splitting into multiple Restricted Keys does not give you extra throughput — it's a permissions boundary, not a quota boundary.
Further reading
- How to get a Stripe Restricted API key — the 4-step Dashboard walkthrough.
- The full permissions map — every scope and what breaks if you untick it.
- A working minimal Restricted Key example — the scope set for a support-refund agent.