Developers
Sitterz API
A small, honest inbound API: issue a token for your workspace, then push contacts and leads into it from your website, your phone system, or whatever else you already run.
What exists today
Sitterz has two token-authenticated endpoints — contact intake and lead intake — plus the portal routes that issue and revoke the tokens themselves. There is no separate API host, no version prefix, and no public read API for bookings, invoices, staff or webhooks. When those arrive they will be documented here, and not before.
Authentication
Create a token in your portal under Settings → Permissions → API tokens (/portal/permissions/api-tokens). Only an account owner can issue one. The secret is shown once, at creation: Sitterz stores only its hash and can never show it to you again.
Send it as a bearer token on every request, against the same host you use for the portal:
curl -X POST https://YOUR-HOST/api/crm/contacts \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-d '{"name":"Dana Reyes","email":"dana@example.com","externalId":"crm-8891"}'The token carries its own workspace and its own role. The workspace is derived from the token — never from a header you send — and every request is run through the same permission check the portal UI uses, so a token can never read or write outside the workspace that issued it and can never exceed the role it was issued with. A token issued read-only, revoked, or expired is known but denied with a 403; a missing or unknown token is a 401.
Endpoints
/api/crm/contactsAPI token · create · customerCreate or update one contact, matched on externalId, then email, then name./api/receptionist/leadAPI token · create · customerFile a caller-keyed lead (externalId and name required) with an optional transcript; retries answer deduped./api/receptionist/leadAPI token · read · customerRead back the leads filed for this workspace./api/portal/settings/api-tokensportal session · ownerList this workspace's tokens (prefix and status only — never a secret)./api/portal/settings/api-tokensportal session · ownerIssue a token. The secret is in the response once and is never stored or shown again./api/portal/settings/api-tokensportal session · ownerRevoke a token by id (?id=…).Contact intake
POST /api/crm/contacts takes a JSON object with a required name and optional email, phone, company, externalId and source (defaults to "api"). Anything else in the body is ignored. It answers { ok, tenantId, created, contact }, where created tells you whether a new record was written or an existing one updated: the match is on externalId first, then email, then name. Send the same externalId twice and you update one record rather than creating two. A malformed email or a missing name is a 400 naming the field.
Lead intake
POST /api/receptionist/lead takes externalId and name (both required) plus optional email, phone and transcript, and files it in your lead inbox. The external id is scoped to your workspace and is not returned. Reusing it leaves the first accepted lead unchanged and answers { ok, tenantId, deduped: true } instead of filing a second one. Names are limited to 200 characters, email addresses to 320, phone numbers to 50, transcripts to 4,000, and malformed email addresses are refused with a 400. GET /api/receptionist/lead reads the inbox back.
This endpoint captures a lead for your business to act on. It does not qualify, score, rank or route anyone — what happens next is your business’s decision.
Rate limits
Every recognized API token has a shared fixed-window quota of 600 requests per minute across all token-authenticated endpoints. The counter is scoped to the workspace and token and is stored in Postgres, so adding an application instance does not multiply the ceiling. A request over the ceiling returns 429 with code api_token_rate_limited and a Retry-After header in seconds.
If a configured production database cannot enforce the shared counter, the request fails closed with 503, code api_token_quota_unavailable, and a short Retry-After. Build your integration to retry network failures, 429, and retryable 5xx responses, and to treat a 401 or 403 as terminal — a token that is refused will keep being refused until you issue a new one.
Both intake endpoints are idempotent on the caller-controlled externalId. Reusing a key for a lead leaves the first accepted payload unchanged, so retry with the same key after a network or retryable server failure.
Need an endpoint that isn’t here? Tell us what you’re building — support@sitterz.com.