Getting started

Authentication

API keys or OAuth, headers, scopes, and how the gateway resolves your workspace.

Every MCP request carries a bearer credential — either an API key or an OAuth access token. The gateway authenticates it, builds a request context (your tenant + permission scopes), and filters which tools your agent can see and call.

Two ways to authenticate

API key (ls_...) OAuth
Best for CI, scripts, headless agents, any client without a native sign-in flow Clients with a built-in "Connect"/"Sign in" button (Claude.ai's remote-MCP connector)
Setup Copy a key from Settings → API Keys, paste it into a header or npx @vlozi/cli auth login Give the client https://mcp.vlozi.app/mcp and click Connect — no key ever created
Lifetime 90 days by default, or never ~1 hour access token, auto-refreshed for as long as the connection stays active
Revoke Settings → API Keys Settings → API Keys → Connected apps

Both are scoped by the exact same permission catalogue — a tool either requires a permission your credential holds, or it doesn't appear in your tool list at all. See MCP clients for setup of either kind.

OAuth

For clients that speak the MCP authorization spec (OAuth 2.1 + PKCE, dynamic client registration), Vlozi is a full authorization server — no manual key required:

  • Discovery: https://mcp.vlozi.app/.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource
  • Registration: https://mcp.vlozi.app/oauth/register (RFC 7591, public clients only — PKCE is the proof of possession, no client secret)
  • Authorize: https://mcp.vlozi.app/oauth/authorize — redirects to a Vlozi consent screen where you pick the permissions the client is granted
  • Token: https://mcp.vlozi.app/oauth/tokenauthorization_code and refresh_token grants

A properly-behaving client handles all of this itself; you never construct these URLs by hand. The access token it ends up with is a short-lived, self-contained credential scoped to whatever you approved — the same PBAC permission strings API keys use, just granted through a consent screen instead of a key-creation form.

API key format

Secret keys start with ls_ and are issued from Settings → API Keys in the Vlozi Dashboard. Shown once at creation; stored hashed.

IMPORTANT

MCP uses the same ls_* keys as the REST API. Same key, same scopes, different endpoint.

Sending the key

Either header works:

# Bearer (preferred)
curl -H "Authorization: Bearer ls_xxxxx" https://mcp.vlozi.app/tools
 
# Or x-api-key
curl -H "x-api-key: ls_xxxxx" https://mcp.vlozi.app/tools

Scopes

Each tool has exactly one required permission. The tool list is filtered to what your key can do — agents never see tools they can't call.

Blog

Scope Tools
blog:posts.read list_posts, get_post, search_posts, list_tags, list_categories, get_analytics
blog:posts.create create_draft, generate_draft, create_category, create_tag
blog:posts.update update_post, update_category, update_tag
blog:posts.publish publish_post, unpublish_post, unschedule_post
blog:posts.delete delete_post, restore_post, delete_category, delete_tag

Brain

Scope Tools
brain:copilot.use query, ingest, list_memories, get_context
brain:memory.delete delete_memory

Contacts

Scope Tools
contacts:contacts.read list_contacts, get_contact_profile, get_contact_channels, get_contact_timeline, export_contact, summarize_contact
contacts:contacts.create create_contact
contacts:contacts.delete merge_contacts, delete_contact
contacts:memory.read list_memories
contacts:memory.delete delete_all_memories
contacts:context.read get_context
contacts:context.write correct_memory
contacts:outreach.read list_outreach, get_outreach_config
contacts:outreach.create schedule_outreach, cancel_outreach, update_outreach_config, trigger_outreach_scan, draft_outreach_message
contacts:analytics.read analytics_trends, analytics_churn, analytics_moods

Newsletter

Scope Tools
newsletter:subscribers.read list_subscribers
newsletter:subscribers.create add_subscriber, unsubscribe_subscriber, tag_subscriber, create_segment
newsletter:subscribers.delete remove_subscriber
newsletter:templates.read list_templates
newsletter:templates.create create_template
newsletter:campaigns.create create_campaign, cancel_campaign, generate_subject
newsletter:campaigns.send send_email, send_campaign

Content (social calendar)

Scope Tools
content:slots.read get_calendar, get_slot
content:slots.write schedule_content, delete_slot, generate_caption, suggest_hashtags
content:slots.approve approve_slot, reject_slot
content:recurring.write create_recurring_schedule
content:connections.read list_connections
content:campaigns.read list_campaigns
content:campaigns.write create_campaign
content:labels.read list_labels
content:labels.write create_label

Chat (chatbot)

Scope Tools
chatbot:config.read list_bots, get_config, list_custom_tools, list_tool_calls, get_audit_log
chatbot:config.write create_bot, delete_bot, update_config, create_custom_tool, update_custom_tool, delete_custom_tool
chatbot:channels.read list_channels
chatbot:channels.write add_channel, connect_whatsapp, delete_channel, set_channel_status
chatbot:sessions.read list_sessions, get_session_messages, summarize_session, draft_reply, analytics_overview, analytics_intents, analytics_models, analytics_sessions_breakdown, analytics_tools, analytics_timeseries
chatbot:sessions.write reply_to_session, assign_session, resolve_session, escalate_session

Comms (transactional email)

Scope Tools
comms:send send_message
comms:sender.read check_alias_availability, get_sender_settings, get_sender_identities
comms:sender.write claim_alias, update_sender_settings, add_suppression, remove_suppression
comms:logs.read list_logs, get_analytics, list_suppression

Collections

Scope Tools
collections:read list_collections, get_collection, list_entries, get_entry
collections:write create_collection, update_collection, delete_collection, create_entry, update_entry, delete_entry, reorder_entries, bulk_delete_entries
collections:entries.publish publish_entry, unpublish_entry

Forms

Scope Tools
forms:read list_forms, get_analytics, get_form, list_submissions, get_submission, list_webhook_deliveries
forms:write create_form, update_form, delete_form, duplicate_form, update_submission, delete_submission, reply_submission, retry_webhook_delivery
forms:submissions.export export_submissions

Flow

Scope Tools
flow:flows.read list_nodes, list_flows, get_flow, get_run_history
flow:flows.create create_flow, update_flow
flow:flows.manage enable_flow, disable_flow, delete_flow

Billing

Scope Tools
billing:coins.read get_balance, get_usage, list_transactions
billing:plans.read get_summary, get_costs

Identify your agent

Pass x-agent-id with a stable per-agent string ("claude-desktop", "n8n-publisher", "content-bot"). It shows up in your audit log so you can tell who did what.

curl https://mcp.vlozi.app/tools/blog.list_posts \
  -X POST \
  -H "Authorization: Bearer ls_xxxxx" \
  -H "x-agent-id: claude-desktop" \
  -H "content-type: application/json" \
  -d '{}'

Tenant resolution

You never send a tenant ID — the gateway derives it from your credential (API key or OAuth token). Both are scoped to exactly one workspace; cross-tenant access is structurally impossible.

Errors

{ "error": { "code": "...", "message": "..." } }
HTTP code Cause
401 invalid_api_key Missing, wrong, revoked, or expired key
401 invalid_token Missing, malformed, or expired OAuth access token — a spec-compliant client silently refreshes and retries; you only see a new consent screen if the underlying connection itself was disconnected or fully expired
403 permission_denied Valid credential, missing required scope
404 tool_not_found Typo or removed tool
400 invalid_input Input failed validation
400 service_error Upstream product service errored
429 rate_limited See Retry-After header

Permission changes propagate within 5 minutes (gateway cache TTL) for API keys. To force-invalidate an API key, rotate it; to force-invalidate an OAuth connection, disconnect it from Settings → API Keys → Connected apps.

Note the OAuth case is immediate for future activity but not instant for one already in flight: disconnecting revokes the refresh token right away, so the client can no longer silently refresh — but an access token it already holds keeps working for up to its remaining lifetime (≤1 hour), since access tokens are self-verified and don't require a database round-trip on every tool call.

MCP · Getting startedEdit on GitHub