Conventions
Base URL
https://api.dokaa.app/v1HTTPS only. All responses are JSON with snake_case field names.
Authentication
Pass your API key on every request:
Authorization: Bearer dk_live_...Each key carries scopes that gate which endpoints it can call, and a
perimeter: the shops it can read. Requests outside the key’s scopes
return 403; unknown or revoked keys return 401.
Scopes
Every key carries scopes that gate which endpoints it can call; enforcement is server-side, on every request. Keys created today carry every read scope. Fine-grained scope selection at creation is planned; the table below shows which scope unlocks which endpoint.
| Scope | Endpoints it unlocks |
|---|---|
shops:read | /shops |
reviews:read | /reviews, /analytics/reviews |
feedbacks:read | /analytics/feedbacks |
contacts:read | /contacts, /analytics/contacts |
campaigns:read | /campaigns |
missed_calls:read | /analytics/missed-calls |
wheel_games:read | /analytics/wheel-games |
audiences:read | /audiences |
google_interactions:read | /google-interactions |
google_posts:read | /google-posts, /google-post-groups, /google-post-groups/eligible-shops, /google-post-groups/{batch_id} |
keyword_tracking:read | /keyword-tracking, /keyword-rankings/summary, /keyword-rankings/trend |
competitors:read | /competitors, /competitors/positioning, /competitors/evolution |
dashboard:read | /summary |
A key’s scopes cannot be extended after creation. Its shop perimeter follows its definition: a key created for a group covers the shops that later join that group.
Shop perimeter
- On multi-shop endpoints, omit
shop_idto query all the shops your key can access at once, or pass it to focus on a single shop. - Competitor and keyword tracking endpoints are single-shop:
shop_idis required on/competitors,/competitors/positioning,/competitors/evolution,/keyword-tracking,/keyword-rankings/summaryand/keyword-rankings/trend. - A
shop_idoutside your perimeter returns403. GET /shopslists your perimeter and the ids to use.
Pagination
List endpoints are cursor-paginated:
{
"data": [ ... ],
"pagination": {
"next_cursor": "eyJkIjoiMjAyNi0w...",
"has_more": true
}
}Pass pagination.next_cursor back as ?cursor= to fetch the next page, until
has_more is false. Cursors are opaque: do not build or modify them. The
default page size is 25, and ?limit= accepts 1 to 100.
Cursor pagination is stable: items created while you paginate can never shift your pages, so exports get every row exactly once.
Dates
- All timestamps are returned in UTC, ISO 8601 (
2026-08-01T09:30:00.000Z). from/tofilters accept ISO dates (2026-01-01).tois inclusive of the whole day.
Errors
Errors follow RFC 9457 Problem Details
with Content-Type: application/problem+json. The type URI identifies the
error kind; its last segment is the stable identifier to match on:
{
"type": "https://api.dokaa.app/docs/errors/invalid-parameters",
"title": "Invalid parameters",
"status": 422,
"detail": "\"from\" must be in ISO 8601 date format"
}| Status | Type | Meaning |
|---|---|---|
| 401 | missing-api-key / invalid-api-key | No key, unknown key, or revoked key |
| 403 | missing-scope | The key lacks the scope this endpoint requires |
| 403 | shop-access-denied | The requested shop_id is outside the key’s perimeter |
| 404 | resource-not-found | The requested resource does not exist or holds no data (unknown batch id, no competitor or ranking snapshot) |
| 422 | invalid-parameters | A query parameter failed validation |
| 422 | invalid-cursor | The pagination cursor is malformed |
| 500 | internal-error | Unexpected error on our side |
Versioning
- Additive changes (new endpoints, new optional fields, new enum values) ship continuously and are always safe: your integration must tolerate unknown fields.
- Breaking changes are exceptional and ship under a new base path
(
/v1→/v2), announced in advance in the changelog./v1keeps working unchanged: you migrate when you choose to.
Every change is listed in the changelog.