Конвенции
Эта страница описывает конвенции, общие для всех эндпоинтов /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 и полный каталог кодов.
- Скоупы и права — какое право нужно, чтобы выдать ключу доступ к каждому ресурсу.