# Best Practices

Habits that keep an integration fast, inside its limits and safe.

Source: https://docs.itsconvo.com/best-practices

API Base URL: https://www.itsconvo.com/api/v1

## React to webhooks instead of polling

Register a webhook for `conversation.keypoints.ready` and read the call when it arrives. Deliveries don't count against your [rate limit](/rate-limits). Webhooks need Professional or Enterprise. On Starter, poll `GET /conversations?since=...` on a schedule.

## Call POST directly for key points and feedback

`POST /conversations/{id}/keypoints` and `POST /conversations/{id}/feedback` return the saved result when there is one, so you don't need a `GET` first. Only `forceRefresh: true` generates again. Key points are free. Generating feedback uses one [AI credit](/tiers#ai-credits).

## Check the error code before you retry

`rate_limited` clears by waiting. `ai_limit_exceeded` doesn't. See [Handling a 429](/rate-limits#handling-a-429).

## Keep your key on the server

Read it from an environment variable and keep it out of front-end code and your repository. If a key leaks, revoke it in the desktop app under **Settings → Convo API** and create a new one.

## Page through long lists

`GET /conversations` returns up to 100 calls per page. Use `offset` until you have `pagination.total` calls.

```javascript
const headers = { Authorization: `Bearer ${process.env.CONVO_API_KEY}` };
const limit = 100;
const calls = [];

for (let offset = 0; ; offset += limit) {
  const res = await fetch(
    `https://www.itsconvo.com/api/v1/conversations?limit=${limit}&offset=${offset}`,
    { headers },
  );
  if (!res.ok) throw new Error(`Convo API ${res.status}`);
  const { data, pagination } = await res.json();
  calls.push(...data);
  if (data.length === 0 || calls.length >= pagination.total) break;
}
```