Skip to content

Authentication

CampaignStack uses API keys for authentication. There are two key types:

Key typePrefixBound toCreated in
User keycsu_Your user account — works across all workspaces you belong toSettings > API Keys
Workspace keycs_A single workspaceWorkspace Settings > API Keys

User keys are the usual choice for personal AI assistants (Claude Desktop, Cursor): one key covers every workspace you’re a member of. Workspace keys are for integrations that should be locked to one workspace, such as a production agent serving a single client.

csu_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
└──┘└──────────────────────────────────┘
prefix 32 hex characters

Keys are a prefix (csu_ for user keys, cs_ for workspace keys) followed by 32 random hex characters (16 bytes of entropy).

  1. Go to Settings > API Keys (user key) or Workspace Settings > API Keys (workspace key)
  2. Click Create API Key
  3. Name the key and select scopes
  4. Copy the key immediately — it’s shown only once

Pass the key as a Bearer token in the Authorization header:

Terminal window
curl -X POST https://mcp.campaignstack.io/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer csu_your_api_key_here" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

The MCP protocol requires an initialize handshake first (the response carries an mcp-session-id header to include on subsequent requests) and an Accept header listing both application/json and text/event-stream. For a quick unauthenticated connectivity check, GET /health returns the server status and tool list.

With a workspace key (cs_), the workspace is implicit — every tool call operates on the key’s workspace.

With a user key (csu_), workspace-scoped tools require an explicit workspaceId argument. Call campaignstack_whoami first: it returns the workspaces you belong to, with their IDs and your role in each.

  • Active — key is valid and can authenticate requests
  • Revoked — key is permanently disabled (soft delete via revokedAt timestamp)
  • Keys track lastUsedAt for auditing
  • Validation results are cached in-memory for 5 seconds, so revoking a key takes effect within ~5 seconds

Each API key is granted a set of scopes that control which tools it can call. Scopes follow the pattern {domain}:{action}.

See the Scopes reference for the full permission matrix.

Call campaignstack_whoami to check your current permissions. With a user key it also lists your workspaces:

{
"keyType": "user",
"keyPrefix": "csu_a1b2",
"scopes": ["campaigns:read", "campaigns:write", "leads:read"],
"user": { "id": "...", "name": "...", "email": "..." },
"workspaces": [
{ "workspaceId": "abc123", "name": "My Agency", "role": "owner" },
{ "workspaceId": "def456", "name": "Client Workspace", "role": "member" }
]
}

With a workspace key it returns the bound workspace:

{
"keyType": "workspace",
"keyPrefix": "cs_a1b2c",
"workspaceId": "abc123",
"workspaceName": "My Agency",
"scopes": ["campaigns:read", "campaigns:write", "leads:read"]
}

This tool requires no specific scope — any valid key can call it.

A user key (csu_) covers all workspaces you belong to with a single MCP server entry — pass the target workspaceId per tool call.

Workspace keys (cs_) belong to exactly one workspace. If you use them to manage multiple workspaces (e.g. one per client), you need a separate API key and MCP server configuration for each:

{
"mcpServers": {
"campaignstack-acme": {
"url": "https://mcp.campaignstack.io/mcp",
"headers": {
"Authorization": "Bearer cs_acme_workspace_key"
}
},
"campaignstack-globex": {
"url": "https://mcp.campaignstack.io/mcp",
"headers": {
"Authorization": "Bearer cs_globex_workspace_key"
}
}
}
}

For internal service communication, CampaignStack supports a separate authentication method using the X-Runner-Secret header with additional context headers (x-workspace-id, x-user-id). This grants all scopes and is used by the runner service.