API Reference
Overview & Conventions

API Reference — Overview & Conventions

Everything that applies to every endpoint, so the per-endpoint pages stay short.

Base URL

Production:  https://accounts.camelcreatives.com
Local dev:   http://localhost:8080

The response envelope

Almost every endpoint returns:

{
  "success": true,
  "data": { "...": "..." },
  "message": "optional human-readable note",
  "errors": ["optional detail strings"]
}
FieldPresent when
successAlways
dataSuccess responses with a payload (omitempty)
messageBoth success confirmations and errors (omitempty)
errorsError details (omitempty)

Exempt endpoints (raw spec JSON)

These return their own format instead of the envelope so standard OAuth libraries work unmodified:

  • POST /oauth/token — OAuth2 token JSON
  • GET /.well-known/openid-configuration — OIDC discovery
  • GET /oauth/jwks — JWKS
  • GET /oauth/userinfo — plain claims map

Status codes in use

CodeMeaning here
200OK (also used for login-with-MFA challenge)
201Created (register, project/client create)
400Validation failure — see message/errors for the reason
401Not authenticated / bad credentials / bad bearer or MFA code
403Forbidden (e.g. archived project)
404Unknown resource (ownership-checked — foreign resources look identical to missing ones)
409Conflict (account already exists)
429Rate limited: "too many requests, try again later"
500Internal failure

Request formats

  • JSON bodies: send Content-Type: application/json
  • Exception: /oauth/token requires application/x-www-form-urlencoded

Cross-cutting behavior

Request IDs

Every response carries an X-Request-Id header (echoes yours if provided, otherwise generates one). Include it in bug reports.

CORS

Enabled per-origin by server config (CORS_ALLOWED_ORIGINS). Allowed origins receive:

Access-Control-Allow-Origin: <your origin>
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Request-Id
Access-Control-Max-Age: 86400

Preflight OPTIONS204 No Content. Note PUT is not allowed — use PATCH. If CORS is not configured on the deployment, browser calls from other origins will fail even though server-to-server calls work.

Timeouts & limits

Per-request timeout of 30 s ({"success":false,"message":"request timed out"}), gzip compression on, request body limit ~1 MiB where applicable. There is no pagination anywhere: list endpoints return full arrays (security events capped at newest 100; audit logs at newest 100).

Rate limits

Redis fixed-window counters keyed by client IP (first X-Forwarded-For hop if present). If Redis is down, limiting fails open — requests are served.

LimiterBudgetApplies to
register5 / min / IPPOST /auth/register
login10 / min / IPPOST /auth/login
social-login10 / min / IPGET /auth/social/{provider}/begin
token30 / min / IPPOST /oauth/token
otp-send3 / hour / IPverify-email/send · verify-phone/send · passkeys/login/begin
admin-login10 / min / IPadmin login
console-project-create5 / hour / IPPOST /console/projects
console-client-create20 / hour / IPPOST /console/projects/{id}/clients

Plus service-level caps independent of IP: max 3 OTP sends/hour per user per channel, max 5 verification attempts per OTP.

Not rate-limited: forgot/reset-password, mfa/*, logout, security-events, profile/connections/sessions reads, console reads.

Authentication models

ModelMechanismUsed by
Browser sessioncamel_session HttpOnly cookie (30-day sliding)All /auth/*, consent, revoke, connections, sessions, console
Bearer tokenRS256 JWT via Authorization: Bearer … (15 min)/oauth/userinfo; also accepted by /profile

401 envelope messages you'll meet: "not authenticated" (no cookie), "session expired or invalid" (bad cookie), "invalid or expired access token" (bearer).

Health

curl -s "$ISSUER/healthz"
# {"success":true,"data":{"status":"ok"}}