How Do You Scope an API Key So a Bot Can't Exceed Its Job?
An unrestricted Stripe secret key can call every Stripe API resource in the account, while a restricted key can be limited to specific actions. GitHub's fine-grained personal access tokens can narrow permissions and repository access compared with a classic token, though a GitHub App is usually the better fit for long-lived organization automation. This guide walks through a dispute-summary bot and a repository PR bot, then shows how to test narrow permissions before production.
AI-assisted editorial: researched and drafted with AI using the primary sources linked below. Examples are illustrative; they are not measured product results. Editorial policy.
Key takeaways
- Use a Stripe restricted key for only the required resources and actions; a classic GitHub token's repo scope is broader than a fine-grained token limited to one repository.
- Map each actual API call to its documented permissions, test the narrow credential in a sandbox, and review request logs or endpoint failures.
- Fine-grained GitHub tokens can be non-expiring unless policy forbids it; choose a deliberate expiry, and consider a GitHub App for long-lived organization bots.
The default key gives your bot everything
When you connect a tool to a bot, the fastest key to grab is usually the one with no restrictions. Stripe calls this a secret key, and any person, agent, or system holding it can do anything in the account: create charges, issue refunds, read customer data, trigger payouts, and more. A bot that only needs to check whether a dispute exists still ends up holding a key that can also move money.
A bot can execute tool calls faster and more repeatedly than a person, so a broad credential raises the cost of a bug or malicious instruction. Application-level approvals can add a pause, but the provider's credential permissions remain the hard ceiling on what the API will accept. Give the bot a key that can perform its intended task and no unrelated action.
Sources: Restricted API keys.
Worked example: scoping a billing bot's Stripe key
Say you're building a bot that checks open disputes each morning and drafts a summary. It never needs to create a charge, issue a refund, or touch a customer record. Stripe's restricted keys let you assign Read, Write, or None to each resource separately, so you create a key with Disputes set to Read and everything else set to None. If that key leaks, an attacker holding it can only read dispute data; they can't create charges, access payment methods, or trigger payouts.
Don't stop at the first guess. After the bot runs for a few days, Stripe's dashboard lets you open the request logs for that specific key and see every call it actually made. Compare that list to the permissions you granted, and remove anything the bot never used. If you're not sure what a key needs up front, you can also work backward from code: search your codebase for Stripe SDK calls and map each one to its permission, for example `Dispute.list(...)` to Disputes: Read.
Sources: Restricted API keys.
Worked example: scoping a repo bot's GitHub token
Now imagine a bot that creates a branch and opens pull requests in one repository. A classic personal access token with the repo scope may work, but GitHub says classic tokens can reach all repositories the owner can access, subject to the owner's own rights and organization policy. A fine-grained token can instead target one resource owner, selected repositories, and named permissions. This is a narrower fit for a bounded personal automation.
For this example's two actions, creating a Git reference requires Contents: Write, and creating a pull request requires Pull requests: Write; Metadata: Read is included with repository tokens. Grant those permissions to the selected repository, then check the exact endpoints the code uses for any additional requirements. Expiration is a choice, not a fixed 366-day requirement: GitHub currently allows a fine-grained token with no expiration unless an organization or enterprise policy limits its lifetime. Set a deliberate short expiry anyway. For a long-lived bot acting for an organization, GitHub recommends a GitHub App rather than a personal token tied to one user's account.
Sources: Managing your personal access tokens - GitHub Docs, REST API endpoints for Git references, REST API endpoints for pull requests.
What goes wrong when the scope is wrong
A scope that is too narrow fails when the bot reaches an endpoint it cannot use. Stripe documents an invalid-request response for missing restricted-key permissions and shows how its per-key request logs identify failures. GitHub's REST endpoint documentation lists the fine-grained permissions required for each call. Test the full workflow, including less common branches, before relying on the key in production; an untested path can still fail later.
Scoping too broad fails quietly. The bot works fine in every normal run, because the extra permissions never get exercised on purpose. The risk only shows up if the key leaks, the bot is prompted into calling something it wasn't meant to call, or a future version of the bot reuses the same credential for a different task than the one it was scoped for. None of that produces an error message before it happens.
- Too narrow: an exercised call is rejected; inspect its response and endpoint permissions during tests.
- Too broad: nothing fails until the key is misused, and by then the damage is whatever the full permission set allows.
Sources: Restricted API keys, Managing your personal access tokens - GitHub Docs.
The decision to make before you connect the tool
Before wiring a credential into a bot, list every provider call the bot's code actually makes, then map each call to the permissions it requires. Some endpoints need more than one permission, so use the provider's current endpoint documentation rather than guessing. Grant only those permissions, restrict repository or resource ownership where supported, and choose an expiry appropriate to the task. Test in a sandbox or limited repository, then review request logs or equivalent evidence and remove unused access.
If you can't yet tell which permissions a bot will need because the task is still being defined, that's a sign to delay connecting a broad key at all. Start with the bot in a read-only or sandbox mode, observe what it tries to do, and scope the real key from that observation instead of from a guess made before the bot ran.
Sources: Restricted API keys, Managing your personal access tokens - GitHub Docs.
Primary sources
Sources checked 2026-10-01. Standards and product documentation can change; follow the linked version when implementing.
- Restricted API keys — Stripe
- Managing your personal access tokens - GitHub Docs — GitHub
- REST API endpoints for Git references — GitHub
- REST API endpoints for pull requests — GitHub
BotBento is in development. Suggest a correction.