Към съдържанието
Sursa Developers

Грешки

Sursa използва HTTP кодовете на статуса, за да каже дали заявката е успяла, и стабилен код на грешка, за да каже защо не е успяла. Всеки отговор с грешка има една и съща структура:

{
  "detail": "the cursor is malformed or was issued for different filters",
  "error": {
    "code": "api.cursor_invalid",
    "message": "the cursor is malformed or was issued for different filters",
    "details": {"parameter": "cursor"},
    "request_id": "01JB7Q2M4X9V3K8T5N6P0R1S2A",
    "doc_url": "https://developers.sursa.com/errors/api.cursor_invalid"
  }
}
ПолеЗначение
error.codeСтабилен код във вида <area>.<reason>. Разклонявайте кода си по него.
error.messageЧетимо обяснение на английски. Може да бъде преформулирано по всяко време; не го анализирайте програмно.
error.detailsСтруктурирани факти за грешката, например параметърът, лимит или кога да опитате отново. Полетата му зависят от кода.
error.request_idID на тази заявка, същото като в заглавката на отговора X-Request-Id.
error.doc_urlСтраницата за този код в този портал.
detailПо-ранният вид на грешката, запазен за съществуващите интеграции. Новият код трябва да чете error.

Всеки код има собствена страница в Кодове на грешки с HTTP статуса му, полетата на details и операциите, които го връщат. Страницата на всяка операция в справочника на API изброява кодовете, които операцията може да върне.

HTTP статуси

СтатусЗначение
200, 201, 202, 204Заявката е успешна. 202 означава, че е приета и все още се обработва.
400Заявката е неправилно съставена: грешен параметър, курсор, metadata или Idempotency-Key. Поправете заявката.
401Няма валиден ключ. Вж. Удостоверяване.
402Достигнат е лимит на плана на организацията, например броят на картите или обемът на хранилището.
403Ключът е валиден, но няма право да прави това: липсва роля, обхват или функция на плана.
404Обектът не съществува или ключът няма право да го вижда.
409Заявката противоречи на текущото състояние: повтарящ се external_id, отворена синхронизация, заявка със същия Idempotency-Key, която все още се изпълнява.
410Срокът на обекта е изтекъл, например на качване след 24 часа, или маршрутът е спрян.
413Тялото или файлът е твърде голям.
415Типът на файла не се поддържа или съдържанието му не съответства на името му.
422Заявката е правилно съставена, но е невалидна: липсва поле или стойност е извън диапазона.
429Твърде много заявки или квотата е изчерпана. Вж. Лимити на честотата и квоти.
500, 502, 503, 504Проблем от страна на Sursa. Опитайте отново по-късно.

Грешки при валидиране

При 422 с кода validation.failed detail изброява всяко поле, което не е преминало проверката, заедно с местоположението му:

{
  "detail": [
    {"loc": ["body", "title"], "msg": "String should have at least 1 character", "type": "string_too_short"}
  ],
  "error": {"code": "validation.failed", "message": "request validation failed", "request_id": "01JB7…"}
}

Кои грешки да опитате отново

ГрешкаПовторен опит?
Мрежова грешка или изтичане на времето за изчакване, няма отговорДа, със същия Idempotency-Key.
429Да, след броя секунди в Retry-After.
500, 502, 503, 504Да, с експоненциално нарастваща пауза: 1 s, 2 s, 4 s… до минута, със случайно отклонение (jitter).
409 api.idempotency_in_progressДа, след Retry-After: първата заявка с този ключ все още се изпълнява.
Всеки друг 4xxНе. Същата заявка пак ще се провали; първо я поправете.

Опитвайте отново заявки POST и PATCH само с Idempotency-Key, за да не може повторен опит след изгубен отговор да създаде втори обект. GET, PUT и DELETE може безопасно да се опитват отново такива, каквито са.

// Retries a request on network errors, 429 and 5xx. The same Idempotency-Key is sent on every attempt.
async function withRetries(send, attempts = 5) {
  for (let attempt = 1; ; attempt++) {
    let response;
    try {
      response = await send();
    } catch (error) {
      if (attempt >= attempts) throw error;
    }
    if (response && response.status !== 429 && response.status < 500) return response;
    if (attempt >= attempts) return response;
    const retryAfter = Number(response?.headers.get("Retry-After"));
    const backoff = Math.min(60, 2 ** (attempt - 1)) * (0.8 + Math.random() * 0.4);
    await new Promise((resolve) => setTimeout(resolve, 1000 * (retryAfter || backoff)));
  }
}

const key = crypto.randomUUID();
const response = await withRetries(() =>
  fetch("https://api.sursa.com/v1/cards/text", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SURSA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": key,
    },
    body: JSON.stringify({ title: "Refund policy", body_markdown: "Refunds take 14 days." }),
  }),
);

Съобщаване за проблем

Всеки отговор, успешен или не, има заглавка X-Request-Id, а всяка грешка има същата стойност в error.request_id. Записвайте я в дневника заедно със собствения си запис за заявката. Когато се свързвате с поддръжката относно заявка, изпратете нейното ID: то води направо до записа за тази заявка.

Обработка на непознати кодове

Нови кодове на грешки може да се появят във всяка версия на API. Обработвайте непознат код по HTTP статуса му: непознат 4xx – като заявка, която няма да успее в този вид, непознат 5xx – като временен проблем.