PendiumDocs

Authentication

How to authenticate with the Pendium MCP server and REST API.

Pendium supports two authentication methods: OAuth (for all MCP connections — Claude.ai, ChatGPT, coding agents, and any MCP client) and API keys (for the REST API and custom integrations).

OAuth (all MCP connections)

All MCP connections use OAuth 2.1 with PKCE. When you add Pendium's MCP server to any client, the platform handles authentication automatically — you sign in with your Pendium account and the platform receives a token.

No API key is needed for MCP. The client registers itself, redirects you to sign in, and exchanges an authorization code for an access token — all behind the scenes.

Tokens are stored hashed, and re-auth revokes the old token. Pendium only persists a SHA-256 hash of each OAuth access token, never the raw value. Signing in again from a new client issues a fresh token and revokes the previous one ("last login wins"), and a revoked token stops authenticating immediately. The platform handles refresh transparently, so you rarely notice.

API key as a bearer-token fallback. Some MCP clients can't run the OAuth flow — Databricks Unity Catalog "Bearer token" connections, n8n, Bruno, and similar low-code tools only let you set a static Authorization: Bearer header. For these, you can connect by passing a personal API key (pendium_… from /settings/api-keys) as the bearer token instead of an OAuth token. OAuth is still the richer, recommended path; use the API key only when OAuth isn't an option.

Supported platforms:

  • Claude.ai (web and desktop app)
  • ChatGPT
  • Claude Code
  • Cursor
  • Windsurf
  • Any MCP-compatible client

See the quick start for setup instructions.

OAuth endpoints (for reference — platforms discover these automatically):

EndpointURL
Protected Resource Metadatahttps://pendium.ai/.well-known/oauth-protected-resource
Authorization Server Metadatahttps://pendium.ai/.well-known/oauth-authorization-server
Dynamic Client Registrationhttps://pendium.ai/register
Authorizationhttps://pendium.ai/authorize
Token Exchangehttps://pendium.ai/token

API keys (REST API only)

For custom integrations, scripts, and no-code tools that use the REST API directly, authenticate with an API key.

Generate an API key from your Pendium dashboard. Log in, click your avatar in the sidebar, then API Keys. Or visit pendium.ai/mcp and click Get API Key. The same dialog lists your existing keys by their short prefix and shows when each was last used, so you can spot and revoke a key you no longer recognize.

Keys are stored hashed. Pendium only persists a SHA-256 hash of your key, never the raw value. The full key (pendium_…) is shown once at creation and can't be recovered afterward — copy it then. If you lose it, revoke it and generate a new one. Revoked keys stop authenticating immediately.

Passing your API key

Include your API key in either of these request headers — pick whichever your HTTP client supports:

x-api-key: pendium_xxxxxxxxxxxx
Authorization: Bearer pendium_xxxxxxxxxxxx

The x-api-key header is the canonical form; Authorization: Bearer is accepted for tools that only support bearer-style auth (Databricks Unity Catalog HTTP connections, Bruno, Insomnia, Postman defaults, n8n).

See the REST API docs for endpoint details and examples.

How auth works

  1. MCP connections: The server extracts the bearer token from the Authorization: Bearer header. It accepts either an OAuth access token (pendium_oauth_…, the default) or a personal API key (pendium_…, for clients that can't run OAuth). Either is validated against Pendium's database, resolving to a user account.
  2. REST API: The server extracts the API key from either the x-api-key header or an Authorization: Bearer pendium_... header. The key is validated by hash lookup, resolving to a user account. OAuth-issued tokens (pendium_oauth_*) are never treated as API keys — those go through the MCP auth path only.
  3. For tools that operate on a specific brand agent (identified by syntheticId), an ownership check verifies the authenticated user has access to that agent.
  4. Admin users can access any agent.

Error responses

When authentication fails, the server returns a 401 with a descriptive error:

ScenarioError message
No token providedAuthentication required. Connect via OAuth.
Invalid or expired tokenInvalid or expired OAuth token. Re-authenticate via OAuth.
No access to agentAgent with syntheticId=X not found or you don't have access. Use the get_account tool to see your agents.

For MCP clients, a 401 response includes a WWW-Authenticate header that triggers the platform to re-authenticate automatically.

Agent access model

Each OAuth token or API key is tied to a Pendium user account. That user owns one or more brand agents (identified by syntheticId). Tools that require a syntheticId parameter will verify that the authenticated user owns that agent before executing.

Use the get_account tool to list all agents accessible to your account, along with their syntheticId values and latest scores.

Content scope

The MCP's blog-post tools (list_blog_posts, publish_blog_post, regenerate_blog_post, generate_blog_post_image, schedule_blog_post, unschedule_blog_post, move_blog_post_to_draft, delete_blog_post, update_blog_post_body, update_blog_post_title, update_blog_post_slug) operate on blog posts only. Social posts are managed in the Pendium app, not over MCP — a blog-post tool given a social postId returns an error directing you there. Blog content itself is generated via the workflow tools (create_workflowrun_workflow_pipeline).

Tool name compatibility

Several tool families were renamed to match the canonical names used everywhere else in Pendium, so one concept has one name across the app, the REST API, and MCP:

Current nameFormer name (deprecated alias)
list_visibility_personaslist_personas
add_visibility_personaadd_persona
update_visibility_personaupdate_persona
delete_visibility_personadelete_persona
list_visibility_topicslist_topics
add_visibility_topicadd_topic
update_visibility_topicupdate_topic
delete_visibility_topicdelete_topic
update_visibility_queryupdate_query
delete_visibility_querydelete_query
list_blog_postslist_posts
regenerate_blog_postregenerate_post
generate_blog_post_imagegenerate_post_image
publish_blog_postpublish_post
schedule_blog_postschedule_post
unschedule_blog_postunschedule_post
move_blog_post_to_draftmove_to_draft
delete_blog_postdelete_post
update_blog_post_bodyupdate_caption
update_blog_post_titleupdate_title
update_blog_post_slugupdate_slug

Only the current names appear in tools/list, but the server still accepts the former names — a tools/call using an old name is transparently routed to its replacement. Existing integrations keep working; new ones should use the current names.

On this page