Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.manticscore.com/llms.txt

Use this file to discover all available pages before exploring further.

ManticScore supports two ways to obtain a session token:
  • Authenticated sessions — start from a Clerk JWT and exchange it for an opaque session token tied to your Clerk user id.
  • Anonymous sessions — start from a stable device id (no sign-in required) and receive a session token tied to an anonymous principal. When the user later signs in, a single rebind call re-owns every anonymous artifact to the authenticated account.
Session tokens are validated in O(1) time on the server, making them significantly faster than repeated JWT verification.

Step 1 — Get a Clerk JWT

Obtain a short-lived Clerk JWT using the Clerk frontend SDK appropriate for your platform. Refer to the Clerk documentation for platform-specific instructions. You’ll use this JWT exactly once: to mint a session token.

Step 2 — Exchange for a session token

Call POST /auth/session with your Clerk JWT in the Authorization header. The server verifies the JWT, creates a session, and returns an opaque session token.
POST /auth/session only accepts a Clerk JWT. You cannot use an existing session token to mint a new one — call this endpoint with your Clerk JWT each time you need to refresh.
curl -X POST https://api.manticscore.com/auth/session \
  -H "Authorization: Bearer <clerk_jwt>"
Request parameters
Authorization
string
required
Your Clerk JWT. Format: Bearer <clerk_jwt>.
Response
200 response
{
  "token": "ms_sess_a1b2c3d4e5f6...",
  "expires_in": 1800
}
token
string
required
Opaque session token. Treat this like a password — store it securely and never log it.
expires_in
number
required
Seconds until the token expires. Always 1800 (30 minutes).

Step 3 — Attach the session token to requests

Include the session token as a Bearer token on every protected endpoint:
Authorization: Bearer <session_token>
curl https://api.manticscore.com/projects \
  -H "Authorization: Bearer ms_sess_a1b2c3d4e5f6..."

Refreshing session tokens

Session tokens expire after 30 minutes. To refresh, call POST /auth/session again with a fresh Clerk JWT before the current token expires. You can do this proactively — for example, refresh 5 minutes before expiry rather than waiting for a 401 Token expired response.
Refresh proactively in long-running apps. If you let the token expire mid-stream, the NDJSON connection will close and you’ll need to reconnect.

Logging out

Revoking a token immediately invalidates it server-side. Any in-flight requests using the revoked token will fail with 401.
curl -X DELETE https://api.manticscore.com/auth/session \
  -H "Authorization: Bearer ms_sess_a1b2c3d4e5f6..."
200 response
{
  "success": true
}

Bootstrap — hydrate your app on launch

After authenticating, call GET /auth/bootstrap as your first API request. It returns your profile, subscription details, and integration secrets in a single round trip. If this is your first sign-in, the server auto-creates your profile.
curl https://api.manticscore.com/auth/bootstrap \
  -H "Authorization: Bearer ms_sess_a1b2c3d4e5f6..."
200 response
{
  "profile": {
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "free",
    "credits_used": 3,
    "credits_total": 20
  },
  "subscription": {
    "plan": "free",
    "credits_used": 3,
    "credits_total": 20
  },
  "secrets": {
    "has_github_pat": true,
    "has_anthropic_key": false
  }
}
profile
object
required
subscription
object
required
Current subscription state. Mirrors the credit fields in profile for convenience.
secrets
object
required

Start an anonymous session

Call POST /auth/anonymous with a stable device_id to mint a session token without any sign-in. Use this on first launch to let users try the product before creating an account. The returned token behaves like any other session token — attach it with Authorization: Bearer <token> on subsequent requests. This endpoint is unauthenticated (no Authorization header required) and idempotent on device_id: calling it again for the same device returns a session bound to the same anonymous principal.
curl -X POST https://api.manticscore.com/auth/anonymous \
  -H "Content-Type: application/json" \
  -d '{"device_id": "<device_id>"}'
Request body
device_id
string
required
Stable per-device identifier (1–200 chars). On iOS, use identifierForVendor or a Keychain-persisted UUID so the same device keeps the same anonymous principal across launches.
Response
200 response
{
  "token": "ms_sess_a1b2c3d4e5f6...",
  "expires_in": 1800
}
token
string
required
Opaque session token for the anonymous principal. Use it the same way as an authenticated session token.
expires_in
number
required
Seconds until the token expires. Always 1800 (30 minutes).
Anonymous writes are tagged internally with a sentinel user_id of the form anon:<uuid>. You should not rely on that string shape — treat the session token as opaque. Once the user signs in and you call POST /auth/rebind, every anonymous artifact is re-owned by the Clerk user in a single transaction.
Errors
StatusBodyCause
422{"detail": "device_id required"}device_id is missing or empty

Rebind an anonymous session to a signed-in user

After a user signs in with Clerk, call POST /auth/rebind with the original device_id and the authenticated session token (or Clerk JWT) in the Authorization header. Every row written under the anonymous principal is re-owned by the authenticated user in a single database transaction, and a durable PostHog alias call is enqueued so conversion attribution survives transient analytics failures.
curl -X POST https://api.manticscore.com/auth/rebind \
  -H "Authorization: Bearer <authenticated_session_token>" \
  -H "Content-Type: application/json" \
  -d '{"device_id": "<device_id>"}'
Request body
device_id
string
required
The same device_id used when calling POST /auth/anonymous. Must be 1–200 chars.
Response
200 response
{
  "rebound": true,
  "rows_updated": 14,
  "anon_uuid": "b1e4..."
}
rebound
boolean
required
true when this call transferred artifacts to the authenticated user. false when the call was a no-op (for example, the device had no anonymous principal, or it was already rebound to the same user).
rows_updated
number
required
Total number of rows re-owned across all user-scoped tables. 0 when rebound is false.
anon_uuid
string | null
required
The anonymous principal UUID that was rebound, or null when there was nothing to rebind.
POST /auth/rebind is safe to call defensively after every sign-in. If the device never used an anonymous session, or the same device/user pair has already been rebound, the call is a no-op and returns {"rebound": false}.
Errors
StatusBodyCause
401{"detail": "Rebind requires an authenticated user token; got anonymous session"}The Authorization header carried an anonymous session token. Sign the user in first, then call rebind with the authenticated token.
409{"detail": "device <id> already rebound to a different user"}This device was previously rebound to a different Clerk user. Human intervention is required.
422{"detail": "device_id and clerk_user_id required"}The device_id field is missing from the body.

Auth error reference

StatusBodyWhat to do
401{"detail": "Missing Bearer token"}Add an Authorization: Bearer <token> header
401{"detail": "Token expired"}Call POST /auth/session to get a new session token
401{"detail": "Invalid token: ..."}Check that the token was copied correctly and hasn’t been tampered with
503{"detail": "JWKS not loaded"}The auth service is temporarily unavailable — retry in a few seconds