Appearance
Authentication
The Actuator API supports two authentication modes:
- Bearer tokens for SDKs, CLIs, scripts, agents, and CI. Send as
Authorization: Bearer act_…. - Session cookies (
actuator_session) for the dashboard. Set automatically when a user redeems a magic-link or accepts an invitation.
If both are set on a request, the bearer token wins.
Base URL
https://useactuator.aiAll paths below are relative to /api/v1 unless otherwise noted.
Errors
Errors come back as a flat envelope:
json
{
"code": "invalid_request",
"message": "email is required",
"fields": { "email": "must be a valid email address" }
}code is machine-readable and stable; message is human-readable and may change. fields is present only on validation errors. See the errors reference for the full code catalog.
Magic-link sign-in
Request a magic link
http
POST /api/v1/auth/magic-link
Content-Type: application/json
{ "email": "user@example.com" }Sends a magic-link email containing a single-use, 15-minute token. Rate-limited to 5/hr per email and 20/hr per IP. Always returns 200 { "sent": true } regardless of whether the email exists, to avoid account enumeration.
Response: 200 → { "sent": true }
Redeem a magic link
http
GET /api/v1/auth/link?t=<raw-token>The endpoint the user clicks from their email. Verifies the token, sets the actuator_session cookie, and 303-redirects to /app/. On failure, redirects to /app/signin?error=<code>.
Response: 303 → /app/ (success) or /app/signin?error=… (failure). Failure codes: magic_link_already_used, magic_link_expired, magic_link_invalid, no_invitation.
Session
Current session
http
GET /api/v1/auth/me
Cookie: actuator_session=…Returns the current user, their email and display name, and the list of organizations they're a member of (with role).
Response: 200 → Session | 401 unauthorized
Sign out
http
POST /api/v1/auth/logout
Cookie: actuator_session=…Deletes the session and clears the cookie. Idempotent.
Response: 204 No Content
Public signup (hosted-only)
Mounted only on the hosted SaaS topology. Self-hosted deploys 404 these routes unless ACTUATOR_PUBLIC_SIGNUP=1 is set.
Discover signup state
http
GET /api/v1/auth/install-stateReturns whether the instance has been claimed (zero orgs = unclaimed) and whether public signup is enabled. The signin page uses this to render the right CTA.
Response: 200 → { "claimed": true, "signupEnabled": true }
Sign up
http
POST /api/v1/auth/signup
Content-Type: application/json
{
"email": "user@example.com",
"displayName": "Pat Doe",
"orgName": "Acme"
}Stages a pending signup, mints a magic-link token, and sends a confirmation email. The user's organization is created when they redeem the link. The org slug is derived server-side from orgName — there's no orgSlug wire field.
Response: 200 → { "sent": true } (always — same enumeration resistance as /auth/magic-link). Errors: 400 invalid_request, 409 slug_unavailable.
First-install bootstrap (self-hosted)
Used once per self-hosted deploy to claim the instance.
http
POST /api/v1/auth/install-claim
Content-Type: application/json
{
"email": "founder@example.com",
"displayName": "Pat Doe",
"orgName": "Acme",
"orgSlug": "acme"
}Atomic: creates the user, the org, and an owner-role membership in one transaction; mints a session and sets the actuator_session cookie. Subsequent calls return 409 already_claimed.
Response: 200 → Session with Set-Cookie: actuator_session=… | 409 already_claimed
Invitation accept (unauthenticated)
Preview an invitation
http
GET /api/v1/invitations/{token}Unauthenticated. Returns the org name, role, and email the invitation was minted for. 404 on unknown / forged token; 410 for terminal states.
Response: 200 → { "orgName", "role", "email" }Errors: 404 not_found, 410 invitation_used, 410 invitation_expired.
Accept an invitation
http
POST /api/v1/invitations/{token}/accept
Content-Type: application/json
{ "displayName": "Pat Doe" }Unauthenticated. The token is the credential. Creates the user (if new), attaches the membership, marks the invitation used, mints a session, and sets the actuator_session cookie — all in one transaction.
Response: 200 → Session with Set-Cookie: actuator_session=…Errors: 404 not_found, 410 invitation_used, 410 invitation_expired, 410 invitation_email_locked.
API tokens
To use the API from a script or SDK, mint a key from the dashboard (Org settings → API keys → Mint key) or via POST /api/v1/orgs/{slug}/api-keys. The raw token is shown once; store it as a secret. Tokens carry a fixed admin-equivalent scope on the org they're minted for and an optional rate-limit cap and TTL.
Send the token on every request:
http
Authorization: Bearer act_…Rate-limit headers come back on every authenticated bearer response with status 2xx, 304, or 429:
X-RateLimit-Limit— requests per minute cap.X-RateLimit-Remaining— requests remaining in the current bucket.X-RateLimit-Reset— integer seconds until the bucket fully refills.
On 429, also Retry-After: <seconds>.