Complete the public API roadmap on top of the existing key-auth layer
(#290). Re-lands POST /api/v1/messages (lost when the stacked #291 never
reached main) by extracting the dashboard send route's core into
`sendMessageToConversation`, then adds:
- Contacts: GET/POST /api/v1/contacts, GET/PATCH /api/v1/contacts/{id}
- Conversations: GET list + /{id} + /{id}/messages
- Broadcasts: POST /api/v1/broadcasts + GET /{id} (persist rows, fan out
in after(), poll for status)
All list endpoints share one keyset-pagination contract
({ data, meta: { next_cursor } }). No migration required — scopes and
tables already exist. Versioned as 0.3.0 (folded into [Unreleased]);
docs/public-api.md updated; outbound webhooks left as the sole roadmap
item. API stays v1 (additive).
Includes fixes from an adversarial code review: cursor validation
against filter injection, broadcast counts deferred to the DB aggregate
trigger, terminal broadcast status reflects failures, duplicate-phone
de-dup, up-front send-param validation (no orphan conversations),
PATCH null-clear semantics, error-checked tag sync, bounded tag filter,
unified audit-user attribution, and a maxDuration on the broadcast
fan-out.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the machine-to-machine auth layer the public REST API needs so
external scripts and automations can drive wacrm (issue #245). This is
the groundwork release; data endpoints land one at a time on top of it.
- Migration 026: account-scoped `api_keys` table. SHA-256 hash at rest
(plaintext shown once), display `key_prefix`, `scopes[]`, RLS via
`is_account_member` (members read, admin+ manage).
- `src/lib/api-keys/`: key gen/hash (wacrm_live_ prefix, timing-safe),
scope vocabulary, service-role auth-path store.
- `requireApiKey(request, scope?)` (src/lib/auth/api-context.ts):
bearer parse -> hash lookup -> liveness -> per-key rate limit ->
scopes-only authz. Returns a service-role-scoped account context.
- `/api/v1` envelope ({data} / {error:{code,message}}) + GET /api/v1/me
reference endpoint that exercises the whole stack.
- Dashboard: admin+ key management routes + Settings -> API keys tab.
- Docs (docs/public-api.md), CHANGELOG, README, .env note.
Checks: typecheck clean, lint 0 errors, full suite green (+27 tests).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>