Authentication
The Agoralia credential model — REST X-API-Key vs OAuth for MCP and the CLI, scopes, rate limits, and idempotency.
Authentication
Agoralia exposes three connect surfaces. They share one workspace and one permission model, but authenticate differently.
| Surface | Credential | Header | Base |
|---|---|---|---|
| REST API | ag_… API key | X-API-Key: ag_… | https://api.agoralia.app/api/v1 |
| MCP | OAuth 2.1 (Bearer) | Authorization: Bearer … | https://api.agoralia.app/mcp |
| CLI | OAuth Bearer (CLI token) | Authorization: Bearer … | https://api.agoralia.app |
The REST API is available on all plans. Abuse is bounded by per-plan rate limits, not by a hard plan gate.
REST: X-API-Key
Create a key in Dashboard → API Keys. Keys start with the ag_ prefix and are
shown once at creation — store it securely, you cannot retrieve it again.
Send it on every request in the X-API-Key header:
curl https://api.agoralia.app/api/v1/me \
-H "X-API-Key: ag_your_key_here"Each key is scoped to a workspace and carries a fixed set of scopes.
A request missing the required scope returns 403 Missing scope: <scope>. Invalid,
malformed (no ag_ prefix), or expired keys return 401.
OAuth: MCP and the CLI
MCP clients and the CLI authenticate with an OAuth 2.1 Bearer token instead of an
ag_ key.
- MCP uses OAuth 2.1 with Dynamic Client Registration (DCR). Your client performs the authorization flow on first connect; you approve a consent screen in the dashboard. See MCP.
- CLI uses a long-lived CLI token you mint in the dashboard (Dashboard → API Keys → "CLI token") and store locally. See CLI.
MCP and the CLI hit the gated agent surface (/pages, /approvals, /actions,
plus gated resource routes), not the /api/v1 REST namespace. Every call is gated
server-side and tagged with the surface in the audit log.
Scopes
API keys carry an explicit list of scopes. A request is rejected with 403 if the key
is missing the scope for that endpoint.
| Scope | Grants |
|---|---|
me:read | Read workspace / account info |
agents:read | List and read agents |
agents:write | Create, update, publish agents |
campaigns:read | List and read campaigns |
campaigns:write | Create and update campaigns |
campaigns:start | Launch / start campaigns |
leads:read | Read campaign leads |
leads:write | Add and update leads |
calls:read | Read calls, transcripts, recordings |
calls:write | Place calls |
results:read | Read call results and analytics |
numbers:read | List phone numbers |
numbers:write | Link BYO numbers, configure inbound, release numbers |
billing:read | Read billing and usage |
compliance:read | Read compliance status |
compliance:write | Manage DNC and compliance |
sms:read / sms:write | Read / send SMS |
webhooks:read / webhooks:write | Read / configure webhooks |
See all scopes for the complete reference.
Grant a key only the scopes it needs. campaigns:start is deliberately separate from
campaigns:write so a key can build campaigns without being able to launch them.
Rate limits
Limits are per-workspace and scale with your billing plan. Over-limit requests return HTTP 429 with a message telling you whether you hit the per-minute or per-day cap.
| Plan | Per minute | Per day |
|---|---|---|
| Free / unknown | 30 | 1,000 |
| Starter | 60 | 5,000 |
| Professional | 120 | 20,000 |
| Business | 300 | 100,000 |
| Enterprise | 600 | 500,000 |
When the limiter backend is unavailable, requests are allowed (fail-open) so legitimate traffic is never blocked by a limiter outage.
Idempotency
Mutating requests accept an Idempotency-Key header. Replaying the same key returns the
stored response instead of performing the action again.
curl -X POST https://api.agoralia.app/api/v1/campaigns \
-H "X-API-Key: ag_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: campaign-2026-06-17-001" \
-d '{"name":"June outreach"}'Reusing the same key with a different request body returns 409 Idempotency key reused with different request body.