Authentication and scopes
Keys
Every request carries your business's API key:
Text
Authorization: Bearer ocost_sk_<id>_<secret>- Made under Settings › API by the owner or the accountant, and shown once. Ocost keeps only a fingerprint: revoke and replace a lost key.
- The start,
ocost_sk_<id>_, isn't secret. Settings lists keys by it, with their scopes and last use; secret scanners spot theocost_sk_prefix in a leak. - One business per key, and never people's papers (pay slips, payroll, health). One Odoo company is one business with its own key.
- Revoking refuses the very next request. A key may also expire on a date.
- At most 10 live keys per business. To rotate, make a new key, switch to it, revoke the old one.
- Server only: never in a browser, a mobile app or a log.
Scopes
Settings › API ticks all three by default.
| Scope | Routes |
|---|---|
documents:write | POST /public/v1/files, DELETE /public/v1/files/{file_id} |
documents:read | GET /public/v1/files, GET /public/v1/files/{file_id}, GET /public/v1/files/{file_id}/content, GET /public/v1/files/{file_id}/document, GET /public/v1/documents/{document_id} |
search:read | GET /public/v1/search |
Refusals
| Answer | When |
|---|---|
401 urn:ocost:key:invalid | No key, or a malformed, wrong, revoked or expired one, or a deleted business's. Always the same answer. |
403 urn:ocost:key:scope | The key lacks the route's scope. |
429 urn:ocost:key:rate | Too many requests, or too many wrong keys from one address. Wait Retry-After seconds. |
400 | An Ocost-View… header, which only Ocost's web app sends. |
Example
curl -sS https://api.ocost.io/public/v1/files \
-H "Authorization: Bearer $OCOST_KEY"import requests
session = requests.Session()
session.headers["Authorization"] = f"Bearer {key}"
files = session.get("https://api.ocost.io/public/v1/files", timeout=15).json()const files = await fetch('https://api.ocost.io/public/v1/files', {
headers: { Authorization: `Bearer ${key}` },
}).then((r) => r.json());