> ## Documentation Index
> Fetch the complete documentation index at: https://build.practicehub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Launch checklist

> What to check before your integration touches a live clinic

Once you've [tested against a developer account](/guides/testing-your-integration), work through this before flipping your integration on against a real clinic. Every box links to the page that explains the reasoning — this page is deliberately just the checklist.

## Credentials

* [ ] **One key per integration, named for what it does** — "Booking widget", "Nightly export" — not one shared key across several systems. Requests and audit trails are per key (the rate limit is shared across the account), and a name that says what a key is for means revoking it later is surgical, not a guess about what else might break. See [Best practices → Credentials](/guides/best-practices#credentials).
* [ ] **Scopes are minimal.** Read-only unless the integration writes; a read-only key can't write anything by construction (`403 key_read_only`), which is the cheapest access control available. See [Authentication → API keys](/authentication#api-keys).
* [ ] **Stored server-side only.** Never in a browser, a mobile app bundle or a public repository — `phk_` keys are recognised by secret scanners, but the fix for a leak is still rotation, not detection. See [Authentication → Rotation, expiry and audit](/authentication#rotation-expiry-and-audit).

## Error handling

* [ ] **`422` is handled by field**, reading `errors` rather than guessing from `message`. `message` is written for a human and can be reworded without notice; the attribute keys in `errors` are the stable part. See [Errors → Handling errors well](/guides/errors#handling-errors-well).
* [ ] **Only `429` and `5xx` are retried**, with exponential backoff and jitter, and the same `Idempotency-Key` reused on every retry of a given `POST` so a retried write can't create the record twice. `409` is retried only after the state that caused it changes; `422`, `401` and `403` are never retried. See [Errors → Retry taxonomy](/guides/errors#handling-errors-well).
* [ ] **The `code` is logged, not just the status.** `rate_limited`, `appointment_rule`, `billing_rule`, `key_read_only` and the rest are stable identifiers your alerting and dashboards should key off — see the full [error code catalogue](/guides/errors#error-code-catalogue).

## Pacing

* [ ] **120 requests per minute, shared across the account's API keys** (AI connectors have their own separate MCP bucket), spent steadily rather than in bursts — firing the whole budget in the first second of every run and idling for the rest of the minute is the surest way to see `429`s (for you and for every other integration on the account) that a paced integration never would. See [Rate limits → Pacing an integration](/concepts/rate-limits#pacing-an-integration).
* [ ] **`Retry-After` is honoured** on every `429`, and `X-RateLimit-Remaining` is watched in normal operation — a value trending toward zero outside of known bulk runs usually means something should be a filter or a cache instead of a poll. See [Best practices → Rate limits and retries](/guides/best-practices#rate-limits-and-retries).

## Data hygiene

* [ ] **Records you create carry your external id in `metadata`** (prefixed with your app name, e.g. `crm_id`) — so you can find, de-duplicate and cross-reference them without keeping a separate mapping table. See [Metadata](/guides/metadata).
* [ ] **The clinic-local vs UTC rule is applied consistently.** `created_at`/`updated_at` (and webhook `occurred_at`) are UTC, for windowing; everything the practice sees — `starts_at`/`ends_at`, `invoice_date`, `payment_date`, availability slots — is clinic-local with no offset, and is sent the same way when you write it. Get this backwards once and every booked time is off by the clinic's UTC offset. See [Best practices → Time](/guides/best-practices#time).

## Monitoring

* [ ] **You know where to look when something's wrong.** The account's **Developers → API Logs** report shows every call your integration makes — status, error code, latency, the calling key — filterable and exportable. Check it during rollout, not just when a user complains. See [Security → Logging and what is stored about your calls](/security#logging-and-what-is-stored-about-your-calls) and [Errors → Diagnosing](/guides/errors#diagnosing).

## Sync correctness

* [ ] **Incremental runs use an `updated_at` watermark with overlap** — filter `updated_at=gte:<watermark>`, sort `updated_at:asc`, walk by cursor, and set the next watermark to when the run *started* (with a few minutes of overlap), not when it finished. See [Best practices → Pagination](/guides/best-practices#pagination).
* [ ] **Deletions are handled via `deleted_entities`**, not inferred from a record disappearing from a list — walk it since your last sync and remove or archive the matching ids on your side. See [Querying → Deleted records](/guides/querying#deleted-records).

## Go-live day

* [ ] **Start with one clinic.** If your integration serves many accounts, turn it on for one first, watch **Developers → API Logs** and your own error rates while it runs for real, and only then roll out to the rest. A problem caught on one clinic is a problem the others never see.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.