<!-- tempo-docs-context -->
> Source: [/docs/accounts/access-keys/scopes](https://tempo.xyz/developers/docs/accounts/access-keys/scopes.md)
> Section: [Accounts](https://tempo.xyz/developers/docs/accounts.md). Create accounts, set up signing methods, policies, access keys, key rotation, and fees, and follow guides for users, automations, agents, and teams.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Scopes

Restricts an access key to the contracts, functions, and recipients its task needs.

## Overview

Scopes are an [access key](https://tempo.xyz/developers/docs/accounts/access-keys)'s allowlist of the contracts, functions, and addresses it can call or pay. They're one of the key's three bounds, with [spending limits](https://tempo.xyz/developers/docs/accounts/access-keys/spending-limits) and [expiry](https://tempo.xyz/developers/docs/accounts/access-keys/expiry).

Tempo reverts any call outside the key's scopes, so a leaked payout key can pay only your payees. A spending limit caps how much the key spends. Scopes decide where it goes. Give every backend, agent, and card key both.

<span id="how-it-works" />

<span id="what-a-scope-restricts" />

## Scope Entries

Each scope entry allows one contract, optionally narrowed to one function and a list of recipients:

| Field | Allows |
| --- | --- |
| `address` | Calls to this contract. |
| `selector` | Only this function, as a signature such as `transfer(address,uint256)` or a 4-byte selector. Omit it to allow every function on the contract. |
| `recipients` | Only these addresses as the recipient of `transfer` or `transferWithMemo`, or as the spender of `approve`. Works with no other function. Omit it, or pass `[]`, to allow any address. |

A call that matches no entry reverts with [`CallNotAllowed`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-callnotallowed). A key without `scopes` can call anything. A key with `scopes: []` calls nothing.

<span id="scopes" />

<span id="scope-an-access-key" />

## Set Scopes

Pass `scopes` when you [authorize the key](https://tempo.xyz/developers/docs/accounts/access-keys#authorize-an-access-key) with Viem's [`accessKey.authorize`](https://viem.sh/tempo/actions/accessKey.authorize) or [`accessKey.signAuthorization`](https://viem.sh/tempo/actions/accessKey.signAuthorization). For example, `{ address: stablecoin, selector: 'transfer(address,uint256)', recipients: [payee] }` lets the key send that stablecoin to `payee` and nothing else.

A key scoped to `transfer` can't call `transferWithMemo(address,uint256,bytes32)`, which payments with a reference use. Give that function its own entry. An Earn deposit needs two entries. One allows `approve(address,uint256)` on the stablecoin, with the vault as recipient. The other allows `deposit(uint256,address,uint256)` on the vault. [Pay out from a backend](https://tempo.xyz/developers/docs/accounts/automations/pay-out-from-a-backend) and [Sweep into Earn](https://tempo.xyz/developers/docs/earn) show complete keys.

<span id="change-allowed-calls" />

<span id="change-a-keys-scopes" />

## Change Scopes

Enough signers to reach the threshold, or an [admin key](https://tempo.xyz/developers/docs/accounts/access-keys/admin-access-keys), change a key's scopes without revoking it. Call `setAllowedCalls` on the [Account Keychain](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain), Tempo's built-in contract that stores access keys. For each contract you pass, it replaces that contract's rules and leaves the others alone. List every rule you want to keep.

Add a second recipient to the key from `access-keys.ts`, the example in [Authorize an access key](https://tempo.xyz/developers/docs/accounts/access-keys#authorize-an-access-key), and allow `transferWithMemo`. List both functions, because the call replaces the stablecoin's rules. The example uses a configurable account, so `client.ts` connects to the Tempo Accounts devnet ([set up the devnet key](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet)). With a single-key account, `setAllowedCalls` works the same on mainnet and testnet.

:::code-group
```ts [set-allowed-calls.ts]
import { toFunctionSelector } from 'viem'
import { Abis, Addresses } from 'viem/tempo'
import { accessKey, account, stablecoin, recipient } from './access-keys'
import { client } from './client'

const newRecipient = process.env.TEMPO_NEW_RECIPIENT as `0x${string}`

await client.writeContractSync({
  account,
  abi: Abis.accountKeychain,
  address: Addresses.accountKeychain,
  functionName: 'setAllowedCalls', // [!code hl]
  args: [
    accessKey.accessKeyAddress,
    [{
      target: stablecoin,
      selectorRules: [
        {
          selector: toFunctionSelector('transfer(address,uint256)'),
          recipients: [recipient, newRecipient], // [!code hl]
        },
        {
          selector: toFunctionSelector('transferWithMemo(address,uint256,bytes32)'),
          recipients: [recipient, newRecipient], // [!code hl]
        },
      ],
    }],
  ],
})
```

```ts [client.ts]
import { http } from 'viem'
import { tempoDevnet } from 'viem/chains'
import { createClient } from 'viem/tempo'

// The Tempo Accounts devnet. Its RPC needs a key, which Tempo gives you.
const rpcKey = process.env.TEMPO_DEVNET_RPC_KEY

export const client = createClient({
  chain: tempoDevnet,
  transport: http('https://rpc-t14-checkpoint.devnet.tempoxyz.dev', {
    fetchOptions: { headers: { Authorization: `Basic ${btoa(`previews:${rpcKey}`)}` } },
  }),
})
```
:::

An entry with `selectorRules: []` allows every function on that contract. To remove one contract from the key's scopes, call `removeAllowedCalls(keyId, target)`.

To read a key's current scopes, call `getAllowedCalls(account, keyId)`. It returns the scope list and `isScoped`, which is `false` for a key that can call anything. A missing, revoked, or expired key reads as scoped with no allowed calls.

<span id="scope-limits" />

## Limits

* Scopes check only the calls the key signs directly. A contract the key can call makes any calls of its own. An allowed factory contract can deploy contracts, even though the key can't deploy one itself. Allow only contracts you trust.
* A limited access key can't change scopes, including its own.
* `setAllowedCalls` reverts with [`InvalidCallScope`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-invalidcallscope) when its list of contracts is empty, or on a zero address or a duplicate entry.
* `setAllowedCalls` and `removeAllowedCalls` revert with [`InvalidKeyId`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-invalidkeyid) on an admin key, which has no scopes.

Specification: [Account Keychain call scopes](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#call-scope-enforcement).

## Related

[Access Keys](https://tempo.xyz/developers/docs/accounts/access-keys): Covers how access keys sign for an account within their bounds.

[Spending Limits](https://tempo.xyz/developers/docs/accounts/access-keys/spending-limits): Covers how much of each TIP-20 token a key can spend.

[Pay Out From a Backend](https://tempo.xyz/developers/docs/accounts/automations/pay-out-from-a-backend): Use for a complete payout key, scopes included.

[Account Keychain Precompile](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain): Covers the contract that stores access keys and checks their scopes.
