Authentication
OwlViz supports **anonymous public reads** and optional **Bearer API keys** for developer identity and plan-based rate limits (Commercial Sprint C1/C2).
Anonymous public reads (default)
Most read routes work without authentication within public IP rate limits (Free tier: 120 global / 60 expensive RPM per IP):
curl -sS "https://api.owlviz.dev/v1/assets/<mint>" -H "Accept: application/json"No account or API key is required for scanner traffic, docs examples, or low-rate exploration.
**C2.7 forced operations** (cache bypass, indexing, media recovery) require a developer API key or monitoring admin token — anonymous callers receive 401 DEVELOPER_KEY_REQUIRED. Ordinary cached reads (GET without refresh=true / force=true) stay public.
API keys
Developers can sign up at [owlviz.dev](https://owlviz.dev), create a **project**, and issue keys from the developer portal (/developer/projects) — **no payment required**. All new accounts start on **Free**; C2 applies Free RPM to keyed traffic without changing the C1 signup → project → key flow.
The same portal exposes **Market Watches** (/developer/market-watches) and **webhooks** (/developer/webhooks) for signed-in accounts. Those pages call dashboard server routes that write with your developer_account identity and plan quotas — you do not need to paste ov_live_ secrets into the browser for CRUD.
| Property | Value |
|---|---|
| Prefix | ov_live_ |
| Header | Authorization: Bearer <api-key> |
| Secret storage | Hashed at rest — raw key shown **once** at creation |
| Plan | Resolved from developer_accounts.plan_id (default **Free**) |
| Rate limits (C2) | Keyed requests bucket by API key ID using plan entitlements |
Example:
curl -sS \
"https://api.owlviz.dev/v1/assets/<mint>" \
-H "Authorization: Bearer ov_live_<secret>" \
-H "Accept: application/json"Plan rate limits (C2)
| plan_id | Global RPM | Expensive RPM |
|---|---|---|
free | 120 | 60 |
builder | 600 | 300 |
pro | 2000 | 1000 |
Free keyed limits match anonymous IP limits. Set plan_id in the database to test Builder or Pro before checkout ships.
Details: [developer-plans.md](./developer-plans.md), [errors-and-rate-limits.md](./errors-and-rate-limits.md).
Key lifecycle
1. **Create** — dashboard returns the full secret once (ov_live_…). A created audit event is stored (actor, timestamp, optional IP/user-agent).
2. **Use** — API resolves the key to a project and plan; updates lastUsedAt.
3. **Revoke** — portal DELETE /api/developer/projects/:projectId/keys/:keyId soft-disables the key (status=revoked, revoked_at set). Revoked keys return 401 INVALID_API_KEY immediately on the public API. Cross-tenant revoke attempts return **404**; unsigned portal calls return **401**.
4. **Rotate** — portal POST /api/developer/projects/:projectId/keys/:keyId/rotate mints a new key, revokes the previous row, and records rotated + created audit events. The new secret is shown once in the response.
5. **Audit** — signed-in owners can list paginated audit events for their project via GET /api/developer/projects/:projectId/keys/audit (optional apiKeyId, limit, before). List endpoints never return raw secrets.
Ops admins on /admin may revoke keys by id (support path); those revokes are logged with actor_type=admin.
Raw keys cannot be recovered from a database leak — only peppered SHA-256 hashes are stored. Plaintext keys are never written to logs.
Errors
| Code | HTTP | Meaning |
|---|---|---|
INVALID_API_KEY | 401 | Missing/invalid/revoked OwlViz key |
DEVELOPER_KEY_REQUIRED | 401 | Forced refresh, indexing, or recovery without key/admin |
API_KEY_AUTH_UNAVAILABLE | 503 | Server missing API_KEY_HASH_PEPPER or database |
RATE_LIMITED | 429 | Plan or IP rate limit exceeded |
Portal key management (session BFF):
| Code | HTTP | Meaning |
|---|---|---|
UNAUTHORIZED | 401 | Sign in required |
PROJECT_NOT_FOUND | 404 | Project not owned by signed-in account |
API_KEY_NOT_FOUND | 404 | Key not found for this account/project |
ALREADY_REVOKED | 409 | Key is already revoked |
Market Watch and webhook writes (API key)
When you send Authorization: Bearer ov_live_…, the API resolves your developer account and plan. You can create and manage **your** Market Watches and webhook endpoints within plan quotas (see [developer-plans.md](./developer-plans.md)):
| Capability | Auth | Quota errors |
|---|---|---|
| Market Watch CRUD | Portal API key | 429 MARKET_WATCH_LIMIT_REACHED |
Market Watch manual tick / refreshNow | Monitoring admin token only | 401 MONITORING_AUTH_REQUIRED |
| Change monitor CRUD | Portal API key | 429 MONITOR_LIMIT_REACHED (min interval 3600s) |
| Webhook CRUD / test | Portal API key | 429 WEBHOOK_LIMIT_REACHED (Free plan: 0 endpoints) |
Keyed list/detail routes only return resources owned by your account. Anonymous callers still have **no** write access.
Change monitor manual check (admin token)
POST /v1/monitors/:id/check remains gated by MONITORING_ADMIN_TOKEN (ops only). Self-serve **create/update/disable** uses your portal API key within plan quotas — see [monitoring.md](./monitoring.md).
Admin-token paths for ownerless operator monitors and legacy workflows remain available when PUBLIC_MONITORING_WRITES is enabled.
See [monitoring.md](./monitoring.md) and [collections.md](./collections.md).
Related
- [Quick start](./quickstart.md)
- [Errors & rate limits](./errors-and-rate-limits.md)
- [Developer plans](./developer-plans.md)