API authentication
Authenticate with a reveal-once site token and the smallest required scopes.
Send the token as a bearer credential:
Authorization: Bearer vc_...
Tokens are created in Dashboard > Connect, belong to one site, and are shown once.
MCP also accepts OAuth sign-in connections; REST continues to use agent keys only. MCP requires authentication up front for initialize, tools/list, server/discover, legacy notifications/initialized and tool calls. OAuth-capable clients such as Claude web, desktop and Code offer Connect or Sign in before tools are available. Existing API-key users keep sending their bearer key on every request.
OAuth protected-resource and authorization-server metadata, trusted Client ID Metadata Documents (CIMD) and public-client registration (DCR) remain public. The static MCP server card and HTTP files under /.well-known/agent-skills/ also remain public; this does not make MCP tool discovery anonymous.
Responses
- No credential: HTTP
401(UNAUTHORIZEDover REST, JSON-RPC-32001over MCP). MCP answers “Sign in required. Connect vibecms in your agent to sign in, or use an agent key from the vibecms dashboard: <APP_URL>/dashboard/connect.” with the sign-in challengeWWW-Authenticate: Bearer resource_metadata="https://app.vibecms.dev/.well-known/oauth-protected-resource/mcp"(using the deployment’s API origin on self-hosted installs), withouterror="invalid_token". REST uses the invalid-credential message below. - Malformed, unknown, expired, revoked, or deleted credential: HTTP
401with the same message on both transports: “This key or sign-in is invalid, expired or was removed. Sign in again, or create a new agent key in the vibecms dashboard: <APP_URL>/dashboard/connect.” Over MCP the challenge also includeserror="invalid_token". - Valid token without the required scope: HTTP
403withFORBIDDEN - Exceeded hosted usage budget: HTTP
429withRATE_LIMIT
MCP and REST calls count against the same hosted workspace budget.
Mutations consume the write budget as well as the call budget over both transports. This includes scheduling or unscheduling a post, rotating a preview link, unarchiving a post, and updating asset metadata. Read-only tools remain available when only the write budget is exhausted.
Limits
Hosted workspaces share these budgets across all keys and calls:
| Free | Paid | |
|---|---|---|
| Calls | 30/minute, 300/day, 1,000/month | 120/minute, 5,000/day, no monthly cap |
| Writes | 50/day, 200/month | 500/day, no monthly cap |
vibecms Cloud allows 120 calls a minute and 5,000 a day, 500 writes a day, and 60 calls a minute per key, with no monthly cap. Free keys allow 20 calls a minute each. A workspace can have at most 10 active keys; only the owner can create or revoke them. Self-hosted installs do not enforce these budgets.
Each key’s per-minute count is independent, including keys on the same blog. Exhausting one key’s minute budget does not block another key while the shared workspace budgets still have room.
Over REST, an over-limit response is HTTP 429 with RATE_LIMIT, a retryAfterSeconds field in the error body, and Retry-After plus X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset / X-RateLimit-Metric / X-RateLimit-Period headers. Over MCP, a quota failure inside tools/call returns an error tool result with code: "RATE_LIMIT" and retryAfterSeconds — no headers; a quota failure on tools/list is an HTTP 429 JSON-RPC error. See error shapes for both MCP shapes.
Quota errors include details.upgradeUrl and “Upgrade to vibecms Cloud: <url>” in the message, pointing to the billing tab in the dashboard configured by APP_URL. MCP tool results carry both fields in their text content and structuredContent; JSON-RPC errors on tools/list carry the link in the message and error.data.details.upgradeUrl. Hand the link to the owner; an upgrade does not remove Cloud’s per-minute or per-day limits.
Storage
Store the token in a secret manager, environment variable, or a local credential file with restricted permissions. Do not embed it in browser code or commit it to a repository.