Snooplytics API DocsHome

Introduction

How the API is structured, how authentication works, and how multi-tenant requests are scoped

3 min read

The API is a multi-tenant REST service. Every endpoint speaks JSON, returns the same response envelope, and uses the same error contract. Tenant-scoped resources live under an organization id carried in the URL path. This page is the mental model you need before calling any endpoint.

Base URL

All examples in these docs use the following base URL. Replace it with your deployment host.

https://api.example.com

Authentication Methods

The API accepts three authentication methods. Pick based on who is calling.

Users sign in through one of the auth endpoints (email + password, magic link, passkey, social, or SSO). A successful sign-in sets an HTTP-only session cookie. Browsers send it automatically when you make requests with credentials: 'include'; a server acting on behalf of a signed-in user must echo the cookie back on each call.

Use this method for browser apps and any server-rendered UI calling the API on behalf of a signed-in user.

Personal Access Token — scripts, CI, integrations

A Personal Access Token (PAT) is a long-lived credential created while signed in (see Quick Start). Send it on every request as:

X-Api-Key: ba_AbCdEf0123456789...

PATs carry an explicit scope list (a subset of the user's permissions) and can optionally be pinned to a single organization.

OAuth 2.1 access token — third-party apps

Third-party applications use the OAuth 2.1 Authorization Code flow against the built-in OIDC provider and call the API with the resulting access token:

Authorization: Bearer eyJhbGciOi...

Use this method when your app acts on behalf of users who are not your own — i.e. a public OAuth integration. There is no password grant.

Organization Context

Most endpoints are tenant-scoped. The authenticated principal may belong to several organizations, so tenant routes carry the active organization id directly in the URL path:

/api/user/organizations/{organizationId}/projects
  • Account routes (/api/user/me, /api/user/oauth-clients, ...) are not tenant-scoped.
  • Tenant routes (/api/user/organizations/{organizationId}/...) require a valid organization id in the URL. Requests without it fail with TENANT_CONTEXT_MISSING.
  • Public routes (/api/public/*) and auth routes (/api/auth/*) are not tenant-scoped.
  • An organization-pinned PAT rejects requests whose :organizationId URL segment does not match the pin.

See API Structure for the full request/response contract.

Route Tiers

Every route belongs to exactly one tier. The tier determines which auth it demands.

TierMountAuthPurpose
Public/api/public/*noneSign-up forms, widgets, health, anonymous tracking
Auth/api/auth/*per endpointSign-in, sign-up, MFA, passkeys, OAuth, SSO
User Account/api/user/*session, PAT, or OAuth token/me, /oauth-clients, ...
User Tenant/api/user/organizations/:organizationId/*session, PAT, or OAuth token + org membershipProjects, payments, members, settings
Webhook/api/webhook/*provider-signed (inbound only)Inbound provider callbacks — never called by you

Request Envelope

Every JSON response uses the same shape:

{
"success": true,
"status": 200,
"code": "OK",
"message": "User fetched successfully",
"data": { "...": "..." },
"meta": { "...": "..." }
}
  • success — boolean, mirrors status < 400.
  • status — HTTP status code as a number.
  • code — machine-readable code (OK on success, VALIDATION_ERROR, NOT_FOUND, RATE_LIMIT_ERROR, ... on failure).
  • message — human-readable summary.
  • data — the resource or resource list on success.
  • meta — pagination, validation error details, or other structured metadata.

See API Structure for pagination and query conventions and Error Handling for the full error code list.

Best Practices

  • Pick the right credential: Sessions for first-party UIs, PATs for headless automation, OAuth Bearer tokens for third-party apps acting on behalf of other users' accounts.
  • Put the organization id in the URL path: Every tenant-scoped route nests under /api/user/organizations/{organizationId}/.... The API never guesses from a default.
  • Store credentials as secrets: Treat PATs and OAuth client secrets like passwords. Use environment variables or a secret manager — never commit them.
  • Request the minimum scopes: PATs and OAuth clients take an explicit scope list. Ask only for what you actually need.
  • Check code, not just HTTP status: The code field is stable; HTTP status classes can shift as the API evolves.
  • Handle 401 and 403 differently: 401 means re-authenticate (session expired / token invalid); 403 means your credential cannot access this resource no matter how you retry.

Next Steps

  1. Make your first call: Follow Quick Start to sign in and issue a PAT.
  2. Learn the envelope: Read API Structure for pagination, headers, and request conventions.
  3. Handle failures: Review Error Handling before you ship.
  4. Budget your calls: Check Rate Limits to understand request budgets.
  5. Lock down scopes: See Scopes & Permissions before creating production keys.