Get started
Authentication
API keys, scopes, headers, and how agent runtimes authenticate to MCP.
Authenticate REST calls with an API key in the X-API-Key header;
MCP agent runtimes use a bearer JWT. The two credential types sit over
one identity surface:
| Surface | Credential | Use case |
|---|---|---|
| REST | API key in X-API-Key |
Server-to-server integrations, scripts, CI |
| MCP | API key or session JWT, as Authorization: Bearer |
Agent runtimes — Claude Code, Cursor, custom |
| Dashboard | Session JWT + refresh + MFA | Humans in the browser |
API keys never grant admin-plane access. Billing, member invites, the credential vault, SSO/SCIM, and tenant settings stay JWT-only. A leaked key has a bounded blast radius — its minted scope set is the maximum reach.
API keys
Minting a key
From the dashboard:
- Sign in.
- Settings → API keys → New key.
- Name it (e.g.
production-erp-sync), pick scopes, copy the plaintext. - The plaintext is shown once. We store a one-way Argon2 hash and cannot recover it. If you lose it, revoke and re-mint.
Keys can also be minted programmatically with the api-keys API using a
user session JWT (an owner or admin whose email is verified) — the
plaintext is returned once. Unknown scopes are dropped against the
catalog below; if every requested scope is unknown the call returns
400 bad_request. API keys themselves cannot mint other keys — key
management requires a user JWT, so a compromised key can never create a
successor with broader scope.
Format
ak_live_dXt8q2Rb_9f3c…6Pk
└┬┘ └┬─┘ └──┬───┘ └───┬───┘
│ │ │ └─ secret (shown once, never stored in plaintext)
│ │ └──────────── public prefix (identifies the key in logs / lists)
│ └────────────────── mode: "live" or "test"
└────────────────────── key marker
Sending a key
API keys go in the X-API-Key header:
X-API-Key: ak_live_…
Authorization: Bearer …is reserved for user/MCP JWTs and is not a valid transport for an API key. Put API keys inX-API-Key.
If your key is scoped to a tenant with more than one organization, add
X-Org-Slug: <slug> to pin the org context.
Test vs live keys
| Prefix | Cost | Notes |
|---|---|---|
ak_test_… |
€0 | Sandbox keys. Refused in the production environment. |
ak_live_… |
Billed | Real traffic. |
Mint test keys for CI; mint live keys for production deployments.
Rotating a key
Rotate a key from the dashboard (or the api-keys API). Rotation keeps the
name, scopes, and expires_at intact and issues a fresh secret, returned
with its plaintext exactly once. Deploy the new key first, then rotate —
the old secret stops working immediately.
Revoking a key
Revoke a key from the dashboard. Revocation is immediate — requests with the
revoked key get 401 (invalid_api_key) from the next request onward.
Listing keys and their scopes
View your keys in the dashboard. The list shows each active key's prefix,
name, scopes, and expires_at — never the plaintext. Key management is
a user-session (owner/admin) operation, so it isn't reachable with an API
key.
Scopes
Scopes follow <resource>:<action>. Mint the narrowest set you can:
a leaked parts:read key cannot trigger a billable calculation, and a
leaked wallet:read key cannot move money.
| Scope | Lets the holder |
|---|---|
parts:read |
List + read parts, revisions, and calculation results |
parts:write |
Create / update / delete parts and revisions, and create + run calculations (billable) |
uploads:read |
List + read existing uploads |
uploads:write |
Upload new CAD / drawings / RFQ text |
webhooks:read |
List webhook endpoints and deliveries |
webhooks:write |
Create / update / delete webhook endpoints |
wallet:read |
Read wallet balance and usage |
audit:read |
Export the audit log (SIEM integration) |
Calculations authorize on
parts:read/parts:write. Finer- grainedparts:calculations:read/parts:calculations:writescopes exist in the catalog for forward compatibility, but calculation endpoints currently enforceparts:read(reads) andparts:write(create + run). To run a calculation, mint a key withparts:write.
Admin scopes don't exist. Plan changes, member invites, SSO/SCIM, credentials, and OAuth provider config are human-dashboard-only. Machine keys cannot reach those surfaces by design.
Required headers
Every authenticated REST request includes:
X-API-Key: ak_live_…
Content-Type: application/json (or multipart/form-data for uploads)
Recommended:
Idempotency-Key: 9c5f-… (UUIDv4 from your client — see Idempotency)
X-Org-Slug: your-org-slug (required only for multi-org tenants)
We stamp X-API-Version and X-Request-ID on every response. Echo
the request id when filing a support ticket — we can pull the
structured log row in one query.
MCP authentication
The MCP server at https://api.arcnm.io/mcp-server/mcp is a bearer-token
protected resource and publishes
RFC 9728 protected-resource metadata
at /.well-known/oauth-protected-resource. The verifier accepts either
credential in the Authorization: Bearer … header:
- an ARCNM API key (
ak_live_…/ak_test_…) — the same key you use for REST, just carried as a bearer token (tried first); or - a tenant-scoped session access token (a JWT, audience-pinned to
/api/v1). Refresh tokens and tokens for other audiences are rejected.
Most agent setups use an API key — it's long-lived, revocable, and
scoped. Supply it to your agent runtime's client config — see
MCP for the exact claude mcp add / Cursor mcp.json
snippets. Note the MCP door only reads the Authorization: Bearer
header — there is no X-API-Key transport on the MCP server (that header
is REST-only).
Verifying webhook payloads server-side
ARCNM signs every webhook with the per-endpoint secret using the
Standard Webhooks scheme. Verify
the webhook-signature header before trusting a delivery — see
Webhooks → verifying signatures.
See also
- Errors —
401 invalid_api_key,403 insufficient_scope. - Rate limits — per-key and per-caller limits.
- Versioning — the
X-API-Versionresponse header. - MCP — bearer auth, tenant scoping, exposed tools.