Skip to main content
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.
Request parameters
string
required
Your Clerk JWT. Format: Bearer <clerk_jwt>.
Response
200 response
string
required
Opaque session token. Treat this like a password — store it securely and never log it.
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:

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.
200 response

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.
200 response
object
required
object
required
Current subscription state. Mirrors the credit fields in profile for convenience.
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.
Request body
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
string
required
Opaque session token for the anonymous principal. Use it the same way as an authenticated session token.
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

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.
Request body
string
required
The same device_id used when calling POST /auth/anonymous. Must be 1–200 chars.
Response
200 response
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).
number
required
Total number of rows re-owned across all user-scoped tables. 0 when rebound is false.
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

Auth error reference