Pooli API

Version 1.0 alpha. This page is the API-hosted summary. The machine-readable contract is the OpenAPI specification (/v1/openapi.json).

Longer narrative examples also live at pooli.app/api-documentation.

Hosts

Use dev-api.pooli.app for development. api-dev.pooli.app does not resolve.

Canonical paths

Canonical user paths are /v1/users/{uid}/.... Canonical organization paths are /v1/organizations/{orgId}/....

Legacy aliases stay supported and are documented in the spec: /users/{uid}/... and /organizations/{orgId}/.... Headings that say /:uid/... mean the canonical /v1/users/{uid}/... path.

Authentication and organization keys

Send Authorization: Bearer <API_KEY>. Create keys in the Pooli app. Keys do not expire. expiresAt is reserved and is not enforced. Rotate a key to issue a new secret while the old one keeps working for a grace period (default 7 days), then the old key and its access tokens stop on the next use. Revoke ends a key immediately.

A key is scoped to the user who created it. Organization routes allow that user when they are the organization owner, an admin, or an active technician. There is no separate organization key. Billing reads are a separate check: owners and admins only.

Read-only organization resources use that same check: customers, routes, stops, invoices, estimates, subscriptions, payments, products, equipment, service visits, and service reports. Canonical paths are /v1/organizations/{orgId}/.... Invoices, payments, estimates, service subscriptions, and billing fields on customers are limited to owners and admins. Technicians still receive customer name, phone, email, address, notes, and pools. Responses omit card data. These routes do not create or update records.

Route dates use the organization time zone when timeZone is an IANA name, or when timeZoneOffset is set in minutes (local minus UTC). If the organization has neither, dates fall back to UTC.

POST /v1/auth/token exchanges a long-lived key for a short-lived Bearer token (15 minutes, 60 minutes maximum). Regenerate invalidates tokens and does not change the key string. Rotate and revoke live under /v1/auth/keys. Clients that send the long-lived key directly still work. X-Pooli-Act-As is owner-only on organization routes. Personal /v1/users routes reject it.

Creates for customers, organization pools, stops, inventory, and reminders require Idempotency-Key (8 to 200 characters). The same key and body replay the first response. A different body returns 409.

Owner or admin writes: customer create, organization pool create, update, and delete, CSV import, and technician status. Technician status accepts active, inactive, or rejected. approved returns 400. Owner, admin, or active technician writes: stop create, and organization log create, update, and delete. Personal /v1/users writes require the path uid to be the key user. Those cover pools, logs, inventory, and reminders, and they reject acting as someone else. Stops store the pool object the app embeds. Reminder create uses the existing reminder scheduler. These writes do not call Stripe and do not accept billing fields.

Errors and pagination

Errors are JSON: { "error", "message", "status" }.

Every list accepts limit, cursor, startAfter (alias of cursor), and envelope=1. The default body remains a JSON array, or null for an empty log page and empty inventory. envelope=1 returns { data, page }.

Legacy spellings

supplimentalSanitizers is the intentional field name. cartrige is the intentional filter spelling used by the app, CSV import, and the value stored when filterCategory is omitted on create. Do not rename either.