# Best practices

## Keys

- **One key per integration.** Revoking one never stops another, and each key's calls show up on
  their own under **View logs**.
- **Only the scopes it needs.** Something that only sends records needs `rows:write` alone.
- **Keys live on servers.** Keep them in environment variables or a secret manager — never in a
  browser, a mobile app or source control. For a form on a web page, use a [Specter form](/forms/overview).
- **Rotate without downtime.** Create the new key, move the integration, then revoke the old one.

## Requests

- **Read before you write.** The board's write guide says what every column accepts; build your
  payload from it instead of guessing.
- **Batch.** Send up to 500 rows in one request instead of one request per row.
- **Page, don't pull everything.** Read large boards with `limit` and `cursor`.
- **Send JSON.** `Content-Type: application/json` on every write.

## Failures

- **Honour `Retry-After`.** On a `429`, wait the seconds it says, then retry.
- **Back off on `5xx`.** Retry with increasing waits; if it persists, send support the answer's
  `X-Request-Id`.
- **Don't retry a `400`.** The message names what is wrong — fix it and resend.
- **Make retries safe.** On page keys, send an `external_id` so a retried write never duplicates.
- **Keep the request id.** Every answer carries an `X-Request-Id` header; log it beside your own
  record so a failure can be traced.
