Snooplytics API DocsHome

Quick Start

Sign in, issue a Personal Access Token, and make your first authenticated call

3 min read

This guide takes you from "no credentials" to a working authenticated request in four steps. You will create an account, sign in to establish a session, issue a Personal Access Token (PAT) for programmatic use, and call a tenant-scoped endpoint with the PAT.

Step 1 — Create an account

Sign up with email and password. This creates the user, provisions a default organization for them, and sends a verification email.

curl -X POST https://api.example.com/api/auth/sign-up/email \
-H "Content-Type: application/json" \
-d '{
  "email": "[email protected]",
  "password": "a-long-secure-passphrase",
  "name": "Your Name"
}'

Sign in via /api/auth/sign-in/email. The API responds with a Set-Cookie containing the session cookie. Browser clients persist it automatically; CLI clients keep a cookie jar and echo it back on each subsequent call.

# -c saves cookies, -b sends them back on later calls
curl -X POST https://api.example.com/api/auth/sign-in/email \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{
  "email": "[email protected]",
  "password": "a-long-secure-passphrase"
}'

The session is now live. You can already call any /api/user/* account route by sending the cookie back. For headless work, continue to Step 3.

Step 3 — Issue a Personal Access Token

Call the API key endpoint while signed in (cookie attached). Choose a short list of scopes — do not ask for every permission. The full token value is returned exactly once; store it immediately.

curl -X POST https://api.example.com/api/auth/api-key/create \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{
  "name": "CI deploy bot",
  "expiresIn": 2592000,
  "scopes": ["user:read", "projects:read", "projects:write"]
}'

Response:

{
"success": true,
"status": 200,
"code": "OK",
"message": "API key created",
"data": {
  "id": "ak_abc123",
  "name": "CI deploy bot",
  "key": "ba_AbCdEf0123456789XyZ...",
  "scopes": ["user:read", "projects:read", "projects:write"],
  "expiresAt": "2026-05-05T10:00:00.000Z"
}
}

Step 4 — Call an authenticated endpoint

Send the PAT via the X-Api-Key header. For tenant-scoped routes (anything touching projects, payments, or members), the URL path carries the organization id. Get yours from GET /api/user/organizations.

# Account route — no organization id required
curl https://api.example.com/api/user/me \
-H "X-Api-Key: ba_AbCdEf0123456789XyZ..."

# Tenant route — substitute the organization id you fetched earlier

ORG_ID="01HZ3K5R4X9Y2V6QF8TJ7W0CDN"
curl "https://api.example.com/api/user/organizations/${ORG_ID}/projects" \
-H "X-Api-Key: ba_AbCdEf0123456789XyZ..."

A successful response looks like this:

{
"success": true,
"status": 200,
"code": "OK",
"message": "User fetched successfully",
"data": {
  "id": "01HZ3K5R4X9Y2V6QF8TJ7W0CDN",
  "email": "[email protected]",
  "fullName": "Your Name",
  "handle": "yourname",
  "isVerified": true,
  "verifiedAt": "2026-04-05T10:05:00.000Z",
  "isActive": true,
  "lastLoginAt": "2026-04-05T10:00:00.000Z",
  "role": "user",
  "organizationCount": 1,
  "createdAt": "2026-04-05T10:00:00.000Z",
  "updatedAt": "2026-04-05T10:00:00.000Z"
}
}

When to use each credential

CallerCredentialHeader sent
Web / admin UI (browser)Session cookieCookie: ... (sent automatically)
Server acting as a signed-in userSession cookie (echoed)Cookie: ...
Scripts, CI, bots, integrationsPersonal Access TokenX-Api-Key: ba_...
Third-party app on behalf of a userOAuth 2.1 access tokenAuthorization: Bearer ...
Enterprise SSO sign-inSession via SSO flowCookie: ...

Best Practices

  • Never ship session cookies to scripts: Sessions are tied to a specific browser. Use a PAT for anything non-interactive.
  • Scope tokens down: Omit projects:write, subscription:write, and api-keys:write from read-only automations. A smaller scope list is a smaller blast radius.
  • Set expiresIn on CI tokens: Rotating on a schedule limits damage if one leaks. Long-lived tokens belong only to infrastructure you trust.
  • Pin tokens to an organization when possible: Pass metadata: { organizationId: "..." } at creation time to lock the token to one tenant. The API rejects any request whose URL :organizationId does not match the pin.
  • Fail loudly on 401 / 403: A 401 means the credential is bad or expired. A 403 means the credential is valid but lacks a scope or does not belong to the requested organization. Retrying will not fix either.

Next Steps

  1. Understand the envelope: Read API Structure for the pagination and response contract.
  2. Handle errors: Review Error Handling.
  3. Respect limits: See Rate Limits.
  4. Choose scopes intentionally: Check Scopes & Permissions before you ship production tokens.
  5. Browse endpoints: Start at the API Keys reference or the Projects reference.