unipile-v2-foundationslisted
Install: claude install-skill henriquecaner/next-level-outreach
# Unipile v2 — Fundamentos (padrão do projeto)
> A v2 é um **redesign real de rotas** — NÃO é `/api/v1/` nem DSN por conta.
> Confirmado empiricamente contra a conta real (OpenAPI 2.16.0).
## Base URL, rotas e auth
- **Base URL: `https://api.unipile.com`** — host central, porta 443. **Não existe
DSN** `apiNN.unipile.com:PORTA` na v2. O dashboard v2 não mostra DSN algum.
- **Rotas: `/v2/{account_id}/...`** — o `account_id` vai no **PATH**, não em query/
body. Ex.: `POST /v2/{account_id}/chats/send`. Rotas account-level (sem conta):
`GET /v2/accounts`, `PATCH /v2/accounts/{account_id}`, `POST /v2/auth/link`.
- **Auth:** header `X-API-KEY: {ACCESS_TOKEN}` em toda requisição a `/v2/*`.
- **OpenAPI (fonte de verdade):** `GET https://api.unipile.com/v2/openapi.json`
(com a X-API-KEY). É a spec completa (servers=[api.unipile.com], ~121 rotas).
- ⚠️ `https://api.unipile.com/admin/*` é a API do **dashboard** (só cookie de sessão;
rejeita a X-API-KEY com 401). Não é a superfície que usamos.
No código, o cliente é `new UnipileProvider('api.unipile.com', apiKey)` → `fetch`
explícito, sem SDK. `UNIPILE_DSN` no env é opcional (default `api.unipile.com`).
## Paginação
Depende do endpoint. `GET /v2/accounts` e as buscas Sales Navigator usam
**`offset`/`limit`** (query) e retornam `has_more`. Alguns endpoints retornam
`cursor`. Nunca assuma "1 página = tudo"; siga `has_more`/`cursor`/`offset`.
## Erros e resiliência
- `res.ok === false` → leia o corpo `{object:"Error", type,