Affinity Design
Agency Guide

Generating API Keys

Create scoped API keys for MCP access with plugin and permission controls

Overview

Every MCP connection starts with an API key. Keys are scoped to a single client and can optionally be restricted to specific plugins or scopes. This lets you grant precisely the right level of access — no more, no less.

Key Format

API keys use the prefix afk_ followed by a cryptographically random string:

afk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6

Important: The raw key is shown exactly once at creation. After that, only the prefix (e.g., afk_a1b2...) is visible in the admin dashboard.

Creating a Key

  1. Go to AdminClients → select a client
  2. Click the API Keys tab
  3. Click Generate New Key
  4. Fill in:
    • Name — descriptive label (e.g., "Claude Desktop — Marketing Team")
    • Scopes — what the key can do (see below)
    • Plugins — which MCP plugins are accessible (optional; leave empty for all)
  5. Click Create
  6. Copy the raw key immediately — you won't see it again

Who Can Create Keys

  • Agency admins can create, edit, and revoke keys for any client.
  • Self-serve business owner accounts (a scoped login tied to one client) can also open API Keys for their own client and generate keys for themselves. They cannot create keys for any other client, and the server rejects any attempt to assign an agency-only plugin to one of their keys, even if it's sent directly to the API.

Quick-Select Presets

The key creation form has two one-click presets:

  • Client scope — selects every plugin and scope that's safe to hand to a client, then replaces whatever was already checked. Available to everyone.
  • Agency scope — selects every registered plugin and scope, including agency-only infrastructure plugins. Only agency admins see this button.

Scopes

Scopes control what platform operations the key can trigger:

ScopeWhat It Allows
outbound:callInitiate voice calls via Twilio
read:callsRead call history and recordings
read:availabilityQuery calendar availability
mcp:accessAccess all MCP tools and resources

Default: ["outbound:call", "mcp:access"]

Plugin Restrictions

By default, a key grants access to all plugins enabled for that client. You can narrow this:

  1. In the key creation form, select Restrict Plugins
  2. Choose from the client-safe plugins:
    • core, ghl, ghl-social, ga4, gbp, github, google-ads, meta-ads, reddit-ads, wordpress, twilio, sendgrid, cloudflare, vercel, communications, verification, image-generation, docs

Example: A marketing team key might only need ga4, meta-ads, google-ads, and gbp.

Agency-Only Plugins

Three plugins run agency-level infrastructure and can never be added to a client-scoped key — the create/edit key form hides them for scoped users, and the server rejects them even if a request tries to add them directly:

PluginWhy it's agency-only
agencyLets an agency key search and switch between every client in the agency's scope.
platform_plugin_updatesRolls out, pauses, or rolls back MCP plugin versions across the whole client fleet.
website-offersManages the agency's shared Website-Day Cloudflare account, GitHub template, and offer-funnel orders.

twilio, cloudflare, sendgrid, and vercel look like they touch agency-owned infrastructure too, since a client often connects through the agency's shared provider account. They're still client-safe: the server enforces a strict tenant boundary underneath (see below), so a client-scoped key on one of these plugins can only ever reach that client's own resources.

Shared-Account Tenant Isolation

Many clients don't have their own Cloudflare, SendGrid, Twilio, or Vercel account — they ride on the agency's shared account instead. A client-scoped key still only reaches that one client's own resources on the shared account:

  • Twilio — ending a call or sending an SMS checks that the phone number belongs to the client first, then authenticates with that client's own resolved Twilio credentials (or the shared agency number, if the client's agencyConnectionAccess.twilio setting allows it). A client key can't hang up or text through another client's number.
  • Cloudflare — a client can't bind their website to a Cloudflare Pages project or DNS zone another client already claimed on the shared account. The full list of the agency's Cloudflare projects and zones is also hidden from client-scoped keys; they only see the projects and zones already bound to their own site.
  • SendGrid — on the shared platform SendGrid key, a client can only send from the platform default sender, their own contact email, a sender already bound to one of their sites, or a sender on a domain their own site serves. The list of available senders and domains shown to a client key is filtered the same way.
  • Vercel — a client-scoped key with no Vercel connection or website binding of its own no longer falls back to the shared platform token. Without an owned connection, Vercel deployment tools report the client isn't connected instead of quietly using the agency's token.

Plugin Enablement Hierarchy

Access is determined by three layers, applied in order:

  1. API key plugins — if set, only these plugins are allowed
  2. Agent enabledPlugins — if the key is used by a specific agent and that agent has plugins configured, those override the client-level list
  3. Client enabledPlugins — the client's default plugin list
  4. All plugins — if none of the above are set

Managing Existing Keys

List Keys

In AdminClientsAPI Keys, you see:

  • Key prefix (e.g., afk_a1b2...)
  • Name
  • Scopes
  • Plugin restrictions
  • Active status
  • Last used timestamp

Edit a Key

  • Rename: Update the descriptive label anytime
  • Change scopes: Add or remove permissions
  • Change plugins: Narrow or expand plugin access
  • Activate/deactivate: Disable without deleting

Revoke a Key

Click Revoke to permanently deactivate a key. This is instant — any connected MCP client will lose access immediately.

Security Best Practices

  • One key per client/purpose: Don't reuse keys across different tools
  • Principle of least privilege: Only grant the plugins and scopes actually needed
  • Rotate regularly: Revoke old keys and generate new ones every 90 days
  • Monitor usage: Check the Last Used timestamp. Unusual gaps may indicate a compromised key
  • Never commit keys: Store them in environment variables or secure vaults, never in code repos

Troubleshooting

"Invalid or inactive API key"

  • Check the key hasn't been revoked
  • Verify the client status is Active (not deactivated or suspended)
  • Confirm the key has the mcp:access scope

"Unknown tool" errors

  • The tool's plugin may not be enabled for this client
  • The API key may have plugin restrictions that exclude the needed plugin
  • Check AdminClientsPlugins to see what's enabled

Key works for some tools but not others

  • Likely a plugin restriction issue. Edit the key and verify the needed plugin is in the allowed list
  • If using agent-level overrides, check the agent's enabledPlugins setting

On this page