EN ZalogujOtwórz Studio
Wersja podglądowa. Katalog modeli, ceny, kalkulator i dokumentacja działają. Generowanie uruchomimy po starcie serwisu.

Błędy

Dokumentacja: spis stron

API odpowiada zwykłymi kodami HTTP. Wszystko z zakresu 2xx oznacza sukces. Pozostałe kody przychodzą z ciałem JSON, w którym pole typu mówi, co się stało - na nim buduj obsługę po swojej stronie.

Jak wygląda błąd

Endpointy /v1/generate, /v1/tasks, /v1/models i /v1/balance zwracają jeden kształt:

json
{ "error": { "type": "insufficient_balance", "message": "Available balance is lower than the estimated cost of this task." } }

Czat zachowuje format błędów z SDK, z którym jest zgodny. Dzięki temu obsługa, którą już masz w kodzie, działa bez przeróbek:

EndpointKształt błędu
/v1/chat/completionsOpenAI: {"error": {"message": "...", "type": "..."}}
/v1/messagesAnthropic: {"type": "error", "error": {"type": "...", "message": "..."}}

Tekst w message piszemy dla człowieka i może się z czasem zmienić. Do decyzji w kodzie używaj statusu HTTP i pola type.

Lista typów

HTTPtypeCo się stałoTwoja reakcja
400invalid_requestZapytanie ma złą budowę, np. zepsuty JSON albo brakuje modelPopraw zapytanie
401authentication_errorKlucza nie ma, ma zły format albo został skasowanySprawdź klucz i nagłówek (Uwierzytelnianie)
402insufficient_balanceDostępne środki nie pokrywają kosztu albo blokadyDoładuj saldo
403permission_errorKlucz wyczerpał miesięczny limit wydatków. Treść: This key reached its monthly spend limit. Create a new key with a higher limit in the dashboard or use another key.Załóż klucz z wyższym limitem albo użyj innego
404not_foundNie ma takiego modelu albo zadaniaPorównaj id z listą w Modelach
422invalid_requestinput łamie input_schema modeluKomunikat wskaże pole do poprawy
429rate_limitKlucz wysyła za dużo zapytańZwolnij i ponawiaj z rosnącą przerwą
429rate_limit_errorKonto ma 25 nieudanych generacji w ostatniej dobie, więc nowe /v1/generate są wstrzymaneOdczekaj tyle sekund, ile podaje Retry-After, i zmień prompt albo parametry
502upstream_errorBłąd po stronie dostawcy modeluPonów po chwili
504timeoutModel nie zdążył odpowiedziećPonów; w czacie spróbuj krótszej odpowiedzi

Limity na klucz

Domyślnie jeden klucz API może wysłać:

EndpointLimit
POST /v1/generate60 zapytań na minutę
/v1/chat/completions, /v1/messages600 zapytań na minutę
POST /v1/generate, generacje nieudane25 na konto w przesuwnym oknie 24 h, potem 429 rate_limit_error z Retry-After

Przekroczenie kończy się 429 rate_limit. Rozciągnij zapytania w czasie albo rozdziel różne prace na osobne klucze.

Porażka zadania to coś innego niż błąd HTTP

Gdy generacja wystartuje, a potem się wywróci, nie zobaczysz kodu błędu HTTP. POST /v1/generate odpowiada 202, a zadanie dopiero później przechodzi w status: "failed" z obiektem error:

json
{ "id": "task_3xq1...", "status": "failed", "error": { "type": "upstream_error", "message": "..." }, "cost": { "amount": "0.00", "currency": "PLN" } }

Zablokowana kwota wraca, koszt wynosi 0. Dlatego przy każdym zakończonym zadaniu sprawdzaj pole status (więcej w Zadaniach).

Co ponawiać, a czego nie

  • Ponawiaj: 429, 502, 504 - z przerwą rosnącą wykładniczo.
  • Nie ponawiaj bez zmiany po swojej stronie: 400, 401, 402, 403, 404, 422. Identyczne zapytanie skończy się identycznie.
  • Nie wysyłaj w kółko zadań, które kończą się status: "failed". Są bezpłatne, ale po 25 porażkach w ciągu doby konto dostaje 429 rate_limit_error i nowe zlecenia czekają do upływu Retry-After. Przed kolejną próbą zmień prompt albo parametry.

Przykładowy wrapper z ponowieniami:

python
import os, random, time, requests

RETRY = {429, 502, 504}

def call(method, url, **kwargs):
    key = os.environ["KADRARIS_API_KEY"]
    headers = {"Authorization": f"Bearer {key}"}
    for attempt in range(5):
        r = requests.request(method, url, headers=headers,
                             timeout=130, **kwargs)
        if r.status_code not in RETRY:
            break
        # 1, 2, 4, 8... s plus losowy rozrzut
        time.sleep(min(2 ** attempt, 30) + random.random())
    if r.status_code >= 400:
        err = r.json().get("error", {})
        raise RuntimeError(
            f"{r.status_code} {err.get('type')}: {err.get('message')}")
    return r

task = call("POST", "https://kadraris.com/v1/generate",
            json={"model": "gpt-image-2.5",
                  "input": {"prompt": "Klaps filmowy na stole"}}).json()
javascript
const RETRY = new Set([429, 502, 504]);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function call(url, init = {}) {
  let res;
  for (let attempt = 0; attempt < 5; attempt++) {
    res = await fetch(url, {
      ...init,
      headers: {
        Authorization: `Bearer ${process.env.KADRARIS_API_KEY}`,
        "Content-Type": "application/json",
        ...init.headers,
      },
    });
    if (!RETRY.has(res.status)) break;
    const wait = Math.min(2 ** attempt * 1000, 30000);
    await sleep(wait + Math.random() * 1000);
  }
  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${res.status} ${error?.type}: ${error?.message}`);
  }
  return res.json();
}

Jeśli używasz SDK OpenAI albo Anthropic, ponowienia masz w pakiecie: oba same powtarzają kilka razy zapytania odbite limitem albo błędem serwera. Liczbę prób zmieniasz parametrem max_retries (Python) lub maxRetries (JavaScript).

python
from openai import OpenAI
client = OpenAI(base_url="https://kadraris.com/v1",
                api_key="sk-kd-...", max_retries=4)

Ostrożnie z ponawianiem /v1/generate

Każde przyjęte wywołanie /v1/generate zakłada nowe zadanie i zamraża pod nie środki. Kiedy twoje połączenie przekroczyło czas i nie masz pewności, czy zapytanie dotarło, nie powtarzaj go automatycznie. Odnotuj zdarzenie w logach, a przy webhookach poczekaj na doręczenie, zanim zlecisz to samo drugi raz.