Scoping API keys to capabilities
Use scopes to limit a Surface API key to selected Capabilities on a Surface. A scoped key invokes only the Capabilities that you specify.
Why scope API keys
Scoping applies least privilege to each integration:
- Each integration gets only the Capabilities that it needs.
- A compromised key can call only the Capabilities in its scope.
Common scope patterns:
- Customer-specific keys. Create one key per customer. For example, give Customer A the FAQ and Order lookup Capabilities, and give Customer B the FAQ Capability only.
- Separate integrations. Create one key per integration. Scope a mobile app key to the Capabilities that the app calls. Scope a public key to selected Capabilities and set key-level rate limits.
- Third-party developers. Give a partner selected Capabilities without exposing the entire Product.
Name each key after its integration and scope. For example, use
Example Organization - FAQ only instead of API Key 3. Descriptive names help you
identify the intended scope when you rotate or delete keys.
Create a scoped key
The dashboard’s Generate API Key dialog sets a key’s name and key type. It does not set scopes. To set scopes, use the API.
Chat Surfaces do not accept Surface API keys. They use client tokens, so the API returns
400 if you create a key on a chat Surface.
-
Get the Surface’s scope targets:
Get the SurfaceEach entry in the
scopeTargetsarray has anidand aname. Copy theidof each Capability that the key needs. -
Create the key with those IDs in
scopes:Create a scoped API keyReplace the following:
YOUR_PRODUCT_ID: the ID of the Product that contains the Surface.YOUR_SURFACE_ID: the ID of the Surface that accepts the key.YOUR_API_KEY: an account API key with permission to create Surface API keys. See Managing API keys.YOUR_SCOPE_TARGET_ID: anidfrom the Surface’sscopeTargetsarray.
-
Store the
keyvalue from the response. A production key’s full value appears only in this response. -
Confirm the key’s scope. The response’s
scopeTargetIdsarray lists the targets that the key can call. Compare it with theidvalues in the Surface’sscopeTargetsarray.
Request body fields
The request body accepts the following fields:
Values accepted in scopes
Use scope target IDs. Each ID matches exactly one target, so the key gets exactly the access that you intend. The API also accepts these values and converts each one to a scope target ID when it creates the key:
- A Capability ID.
- A Capability name from the
namefield inscopeTargets. The name must match exactly one target.
A scopes array that contains "*" is unrestricted.
You can also create a scoped key through the
Runtype MCP server. The create_surface_key tool
accepts the same scopes values, and the get_surface tool returns scopeTargets. The
tool creates test keys only.
Fix scope errors
If a scope value is not valid, the API returns 400 with one of these codes:
INVALID_SURFACE_KEY_SCOPE: the value is blank, or it does not match a Capability on this Surface. Check the value against the Surface’sscopeTargetsarray.AMBIGUOUS_SURFACE_KEY_SCOPE: the name matches more than one target. Use the scope target ID instead.
How scopes apply on each Surface type
When a scoped key calls a Capability outside its scope, the response depends on the Surface type. Handle these errors by status code or error code, not by message text.
The API 403 response has this form:
On API, MCP, and A2A Surfaces, each skill of an external agent is a separate scope target. To grant one skill, use that skill’s scope target ID. To grant every skill of the agent, use its Capability ID.
When the Surface changes
A scoped key keeps the scope targets it had when you created it:
- A Capability that you add to the Surface later is not available to existing scoped keys. Unscoped keys get it automatically.
- If you remove a Capability from the Surface and add it again, it gets a new scope target ID. Scoped keys lose access to it without an error at the time of the change.
After either change, create a new scoped key and make a test call to confirm access.
Change a key’s scope
You cannot update a key’s scopes after you create it. Neither the API nor the dashboard has a control for it. Delete the key, and then create another key with the scopes that you need.
Use unscoped keys
Use unscoped keys only for integrations that need every Capability exposed through the Surface. A compromised unscoped key can invoke every Capability on that Surface. Rotate unscoped keys on a regular schedule.
Next steps
Continue with these guides:
- Authenticating with product API keys: configure authentication headers and manage keys
- Calling your API endpoints: send requests and process responses
- Setting up an API Surface: create and configure an API Surface
- MCP authentication: authenticate MCP clients with Surface API keys
- How A2A works: call Capabilities through an A2A Surface
- Managing API keys: create the account API key that manages Surface API keys