Документація API

Інтеграція біржі SAMO-TRANS у вашу TMS або CRM

Документація API

Помилки

Сталий конверт відповіді та повний перелік кодів помилок із поясненнями.

Будь-яка помилка приходить в одному й тому самому конверті — незалежно від ендпоінта й причини:

{
  "error": {
    "code": "validation_error",
    "message": "capacity must be a number",
    "requestId": "0f2b8c1e-6a4d-4a4b-9a30-1c9a2e5f8b77"
  }
}
  • code — стабільний машинний код. Він не змінюється й саме за ним потрібно писати логіку.
  • message — пояснення для людини. Формулювання може змінитися будь-коли, не парсіть його.
  • requestId — унікальний ідентифікатор запиту. Логуйте його: за ним підтримка знайде конкретний виклик у логах сервера.

HTTP-статус завжди узгоджений із кодом, тож перевіряти можна будь-що з двох — але code точніший: два різні коди можуть ділити один статус.

Перелік кодів

КодHTTPКоли трапляєтьсяЩо робити
unauthorized401немає заголовка Authorization, ключ хибний, відкликаний або тариф компанії більше не містить APIперевірити ключ і тариф; повторювати без змін немає сенсу
forbidden403ключу бракує потрібної області доступу; запит з IP поза переліком дозволених; немає прав на конкретну заявкувидати ключ із потрібними областями або виправити перелік IP
not_found404об'єкта не існує або він належить іншій компаніїперевірити id; API навмисно не розрізняє ці два випадки
conflict409інший запит із тим самим Idempotency-Key ще виконуєтьсяповторити за 1–2 секунди
validation_error400, 422не пройшли валідацію тіло чи параметри; надіслано зайве поле (наприклад companyId); той самий Idempotency-Key використано з іншим тілом (422); заявку піднято занадто рано або вичерпано ліміт піднятьвиправити запит; повтор без змін дасть той самий результат
rate_limited429перевищено ліміт запитів за хвилинузачекати згідно з Retry-After
quota_exceeded429вичерпано добову квоту записівпродовжити наступної доби; Retry-After показує, скільки лишилось
internal5xxзбій на нашому боціповторити з експоненційною затримкою; якщо повторюється — надіслати requestId у підтримку

Чому кодів саме стільки

Внутрішні причини відмови навмисно не виносяться в окремі коди. Наприклад, спроба підняти заявку може провалитися через «занадто рано» або «вичерпано ліміт піднять» — обидві приходять як validation_error, а конкретна причина лишається в message. Так набір кодів залишається маленьким і стабільним: інтеграція, написана сьогодні, не зламається, коли на бекенді з'явиться нова перевірка.

Із цього випливає практичне правило: розгалужуйте логіку за code, показуйте користувачеві message, у підтримку надсилайте requestId.

Приклади

Немає заголовка авторизації:

{ "error": { "code": "unauthorized", "message": "Missing API key", "requestId": "…" } }

Ключ без потрібної області:

{ "error": { "code": "forbidden", "message": "Insufficient API key scope", "requestId": "…" } }

Зайве поле в тілі (тут — companyId, який завжди береться з ключа):

{ "error": { "code": "validation_error", "message": "property companyId should not exist", "requestId": "…" } }

Вичерпано добову квоту:

{ "error": { "code": "quota_exceeded", "message": "Daily write quota exceeded", "requestId": "…" } }

Обробка на клієнті

async function call(path, init) {
  const res = await fetch(`${API_BASE}/api/public/v1${path}`, init);
  if (res.ok) return res.json();

  const { error } = await res.json();
  switch (error.code) {
    case "rate_limited":
    case "quota_exceeded":
      throw new RetryableError(error, Number(res.headers.get("Retry-After") ?? 60));
    case "internal":
      throw new RetryableError(error, 5);
    case "unauthorized":
    case "forbidden":
      throw new ConfigurationError(error); // повтор не допоможе — потрібне втручання
    default:
      throw new RequestError(error); // виправляйте запит
  }
}