The surface the dashboard itself runs on. Two credentials, deliberately kept apart: a session cookie says who you are, an org token says which workspace a request may touch.
Signing in sets an HttpOnly session cookie. That cookie is not sufficient to read workspace data — you exchange it for a workspace-scoped bearer token, and the exchange is where membership is checked.
bash
# 1. sign in — sets the session cookie
curl -c jar.txt -X POST https://api.zealoop.com/api/auth/login \
-H 'content-type: application/json' \
-d '{"email":"you@company.com","password":"…"}'
# 2. see which workspaces this account can open
curl -b jar.txt https://api.zealoop.com/api/auth/me
# 3. trade the session for a workspace token
curl -b jar.txt -X POST https://api.zealoop.com/api/auth/token \
-H 'content-type: application/json' \
-d '{"orgId":"org_…"}'
# 4. use it
curl -H "Authorization: Bearer <token>" \
https://api.zealoop.com/api/org/org_…/settings
Responses
Every response is JSON with a success boolean. Successful reads carry data, and lists add total. Failures carry error with a message written for a human.
json
{ "success": true, "data": { … }, "total": 353 }
{ "success": false, "error": "You don't have access to that workspace" }
Google and GitHub sign-in are a browser redirect, not a fetch: send the visitor to /auth/google or /auth/github, and the callback sets the session cookie and returns them to the dashboard.
The public surface the browser widget talks to, under /api/widget. It authenticates with your workspace public key rather than a bearer token, and identity is established with the signed payload described in Identity & signing.
Limits are counted per minute. Going over returns 429 with a Retry-After header giving the seconds to wait — back off for that long rather than retrying in a loop.
Widget and chat requests: 60 per visitor, 60 per IP address, and 300 per workspace.
Sign-in attempts: 30 per IP address and 10 per account.