Конвенції
Ця сторінка описує конвенції, спільні для всіх ендпоінтів /api/v1: базову адресу, формат відповідей, заголовки, пагінацію, роботу з датами та фільтрами. Якщо для конкретного ендпоінта конвенцію не перевизначено в Довіднику ендпоінтів — діє те, що описано тут.
База та версії
Базова адреса API — https://smengo.com/api/v1. Версія закріплена в шляху: зворотно несумісні зміни виходитимуть як /api/v2, а не як правки поточної версії — наявні інтеграції не зламаються непомітно.
API доступний лише по HTTPS. Відповіді не кешуються: кожна відповідь позначена Cache-Control: private, no-store, бо дані прив'язані до конкретного API-ключа.
Формат відповіді
Список ресурсів
Успішна відповідь для списку — об'єкт із data (масив) та meta.next_cursor:
{
"data": [
{ "id": "9c1a2e34-5678-4abc-9def-0123456789ab", "...": "..." }
],
"meta": { "next_cursor": "eyJrIjoiSXZhbm92YSIsImlkIjoiOWMxYS4uLiJ9" }
}
meta.next_cursor дорівнює null, якщо це остання сторінка.
Одиничний об'єкт
Ресурси, яких в організації рівно один (наприклад, GET /org), повертають об'єкт без meta:
{ "data": { "name": "Coffee & Co", "slug": "coffee-co", "timezone": "Europe/Kyiv" } }
Помилка
Усі помилки повертаються в єдиному envelope — незалежно від ендпоінта та причини:
{
"error": {
"code": "validation_error",
"message": "Invalid query parameters.",
"hint": "from must not be later than to.",
"docs_url": "https://smengo.com/api-docs/reference/errors#validation_error",
"request_id": "8f14e45f-9e05-4f1a-8a3e-3d2b1c0f9b1b"
}
}
Повний каталог кодів помилок і що з кожним робити — на сторінці Помилки. Текстових відповідей у API немає — лише JSON, завжди, включно з помилками.
Заголовки відповіді
X-Request-Id— uuid v4, присутній на всіх відповідях/api/v1, включно з помилками. Вказуйте його, звертаючись у підтримку — за ним знаходиться конкретний запит у логах.Cache-Control: private, no-store— відповіді не призначені для кешування ані браузером, ані проксі.
Пагінація
Списочні ендпоінти використовують cursor-пагінацію:
?limit=— ціле число1..200, за замовчуванням100.?cursor=— непрозорий base64url-рядок ізmeta.next_cursorпопередньої відповіді. Не збирайте його вручну — просто передавайте як є в наступний запит.- Порядок сортування фіксований для кожного ресурсу та завжди включає
idяк тай-брейкер (наприклад, співробітники сортуються заfull_name, id). Тай-брейкер гарантує, що сторінки не дублюють і не пропускають рядки за однакових значень основного поля сортування. - Курсор, який зіпсований або належить іншому набору даних (наприклад, отриманий з іншими фільтрами) —
400 invalid_cursor.
curl -s "https://smengo.com/api/v1/employees?limit=50&cursor=eyJrIjoiSXZhbm92YSIsImlkIjoiOWMxYS4uLiJ9" \
-H "Authorization: Bearer smg_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Обмеження частоти
Кожен API-ключ обмежений rate_limit_per_min запитів на хвилину — за замовчуванням 60, ліміт налаштовується індивідуально для конкретного ключа. Вікно ковзне (sliding window, у стилі Cloudflare): під час підрахунку поточної хвилини частково враховується частка хітів попередньої хвилини, тому різкий сплеск рівно на межі хвилини не дає змоги обійти ліміт подвоєною кількістю запитів.
Три заголовки присутні на кожній відповіді /api/v1 — і на успішних, і на помилках:
| Заголовок | Значення |
|---|---|
X-RateLimit-Limit |
Ліміт ключа, запитів/хв. |
X-RateLimit-Remaining |
Скільки запитів залишилося в поточному вікні. |
X-RateLimit-Reset |
Unix-час (секунди), коли поточне вікно закінчиться і ліміт обнулиться. |
За перевищення ліміту відповідь — 429 rate_limited з додатковим заголовком Retry-After (секунди до наступної спроби):
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1784625300
Retry-After: 42
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded.",
"docs_url": "https://smengo.com/api-docs/reference/errors#rate_limited",
"request_id": "8f14e45f-9e05-4f1a-8a3e-3d2b1c0f9b1b"
}
}
Докладніше про код помилки — в Помилках → rate_limited.
Запити, відхилені на етапі автентифікації або перевірки скоупу (401 unauthorized, 403 missing_scope, 403 subscription_inactive), ліміт не витрачають — рахуються лише запити, що дійшли до самого лімітера.
Дати та час
- Поля-дні (
entry_date,date,period,from,to) — форматYYYY-MM-DD, у таймзоні організації, не в UTC. - Інстанти (
check_in_at,created_at,updated_at, …) — ISO 8601 UTC із суфіксомZ:2026-07-01T09:00:00.000Z. - Таймзона організації доступна у відповіді
GET /org(полеtimezone).
Фільтри
Застосовується до всіх часових ресурсів: schedule-entries, check-ins, timesheets, demand-signals.
from,to—YYYY-MM-DD, у таймзоні організації, межі включно.fromне може бути пізніше заto; максимальний діапазон — 366 днів; порушення будь-якої умови —400 validation_errorіз поясненням уhint. Якщо параметри не передані — за замовчуванням використовується поточний місяць у таймзоні організації, тому запит взагалі без параметрів уже повертає змістовні дані. Дляtimesheetsfrom/toзіставляються заperiod— першим днем місяця, якому належить табельний запис.department_id— доступний скрізь, де в ресурсу є відділ (зокрема наemployees); фільтр — строга рівність.employee_id— доступний наschedule-entries,check-ins,timesheets.- Невідомий
department_id/employee_id, зокрема той, що належить чужій організації, — не помилка: просто порожній список. Так тенант-ізоляція не дає змоги перебором перевірити існування чужих ідентифікаторів. from/toна ресурсі без часового виміру (org,departments,employees,shift-presets,status-types) —400 validation_error: зайвий параметр не ігнорується мовчки, а відхиляється явно.
Що далі
- Помилки — формат envelope і повний каталог кодів.
- Скоупи та права — яке право потрібне, щоб надати ключу доступ до кожного ресурсу.