Dokumentacja / Szybki start

Obsługa błędów

5 min czytania

Ten przewodnik wyjaśnia odpowiedzi błędów z MailingAPI i jak je prawidłowo obsługiwać.

Format odpowiedzi błędu

Każdy błąd ma ten sam format JSON:

{
  "error": {
    "code": "validation_failed",
    "message": "Błąd walidacji",
    "details": {
      "subject": ["can't be blank"]
    }
  }
}

Pola:

  • code — Stabilny, maszynowo czytelny kod błędu. W swojej integracji rozgałęziaj logikę po code.
  • message — Opis czytelny dla człowieka. Służy do logów i do ludzi, dla niektórych błędów może być po polsku i może się zmieniać — nigdy nie rozgałęziaj logiki po message.
  • details — Tylko dla validation_failed. Mapa: nazwa pola → lista komunikatów.
  • retry_after — Tylko przy 429. Liczba całkowita, w sekundach.

Kody statusu HTTP

Kod Znaczenie Kiedy występuje
200 OK Żądanie zakończone sukcesem
201 Created Zasób utworzony
202 Accepted Operacja asynchroniczna w kolejce
400 Bad Request Nieprawidłowo sformułowane żądanie
401 Unauthorized Brak lub nieprawidłowy klucz API
403 Forbidden Prawidłowy klucz, ale akcja niedozwolona
404 Not Found Zasób nie istnieje
409 Conflict Zasób już istnieje lub żądanie idempotentne wciąż się przetwarza
413 Payload Too Large Body żądania przekracza 25 MB
422 Unprocessable Walidacja pól nie przeszła lub ponownie użyty klucz idempotencji
429 Too Many Requests Przekroczony limit żądań lub wysyłki
500 Server Error Coś poszło nie tak po naszej stronie

Kody błędów

HTTP code Znaczenie Ponawiać?
400 bad_request Nieprawidłowe żądanie, np. niepoprawny adres nadawcy, batch powyżej 1000, brak messages / recipient_variables Nie
400 invalid_idempotency_key Idempotency-Key jest pusty lub dłuższy niż 255 znaków Nie
401 missing_auth, invalid_auth, invalid_key, insufficient_permissions, ip_not_allowed Problem z uwierzytelnieniem lub uprawnieniami Nie
403 forbidden Np. nadawca nie jest z domeny klucza API Nie
403 organization_not_active, domain_not_verified, api_key_without_domain, daily_limit_reached, monthly_limit_reached, ip_blocked Stan konta lub planu Nie — najpierw napraw stan konta
404 not_found Zasób nie istnieje Nie
409 idempotency_request_in_progress Pierwsze żądanie z tym samym Idempotency-Key wciąż się przetwarza Tak, po Retry-After sekundach
409 conflict Zasób już istnieje (np. rejestracja konta z istniejącym emailem) Nie
422 validation_failed Walidacja pól nie przeszła, patrz details Nie
422 idempotency_key_reused Ten sam klucz z innym body Nie
429 rate_limit_exceeded Limit żądań API na sekundę / minutę Tak, po Retry-After sekundach
429 daily_limit_exceeded Dzienny limit wysyłki domeny; retry_after = sekundy do północy UTC Tak, po Retry-After sekundach
429 recipient_rate_limited Maks. 10 emaili na godzinę i 50 na dobę do tego samego odbiorcy w organizacji; retry_after = sekundy do najbliższej pełnej godziny (limit godzinowy) lub do północy UTC (limit dobowy) Tak, po Retry-After sekundach
500 internal_error Coś poszło nie tak po naszej stronie Tak, z exponential backoff; użyj tego samego Idempotency-Key

Błędy autentykacji i uprawnień (401, 403)

{"error": {"code": "invalid_key", "message": "Invalid API key"}}

Rozwiązanie: Sprawdź, czy klucz API jest poprawny i aktywny, ma wymagane uprawnienia, a adres from należy do domeny klucza.

Błędy walidacji (422)

{
  "error": {
    "code": "validation_failed",
    "message": "Błąd walidacji",
    "details": {
      "to": ["can't be blank"],
      "subject": ["should be at most 998 character(s)"]
    }
  }
}

Rozwiązanie: Sprawdź obiekt details i popraw każde pole.

Błędy rate limit (429)

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "retry_after": 5
  }
}

Każda odpowiedź 429 zawiera standardowy nagłówek Retry-After (liczba całkowita sekund) oraz retry_after w body, z tą samą wartością. Zalecamy czytanie nagłówka Retry-After. Odpowiedzi 429 dla limitu na sekundę i na minutę zawierają też nagłówki X-RateLimit-*; odpowiedzi 429 dla limitu dziennego zawierają X-Daily-Limit i X-Daily-Remaining: 0. Zobacz Przegląd API → Rate limiting.

Rozwiązanie: Poczekaj Retry-After sekund, potem ponów żądanie.

Błędy zasobów (404, 409)

{"error": {"code": "not_found", "message": "Message not found"}}

Rozwiązanie: Zweryfikuj ID zasobu lub sprawdź duplikaty.

Obsługa błędów w kodzie

Python

import requests
from requests.exceptions import HTTPError

try:
    response = requests.post(
        "https://api.mailingapi.com/v1/messages/send",
        headers={"Authorization": f"Bearer {api_key}"},
        json=payload
    )
    response.raise_for_status()
    result = response.json()

except HTTPError as e:
    error = e.response.json().get("error", {})

    if e.response.status_code == 401:
        # Ponowna autentykacja lub sprawdzenie klucza
        handle_auth_error()
    elif e.response.status_code == 429:
        # Respektuj rate limit: nagłówek Retry-After, w sekundach
        retry_after = int(e.response.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        # Ponów żądanie
    elif e.response.status_code == 422:
        # Zaloguj błędy walidacji (rozgałęziaj po error["code"], nie po message)
        logger.error(f"Validation failed: {error}")
    else:
        # Nieoczekiwany błąd
        logger.error(f"API error: {error}")
        raise

JavaScript

async function sendEmail(payload) {
  try {
    const response = await fetch('https://api.mailingapi.com/v1/messages/send', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    });

    if (!response.ok) {
      const { error } = await response.json();

      switch (response.status) {
        case 401:
          throw new AuthenticationError(error.message);
        case 429:
          // Nagłówek Retry-After jest w sekundach
          const retryAfter = Number(response.headers.get('Retry-After')) || 60;
          await sleep(retryAfter * 1000);
          return sendEmail(payload); // Ponów
        case 422:
          throw new ValidationError(error.code, error.details);
        default:
          throw new APIError(error.message, error.code);
      }
    }

    return response.json();

  } catch (error) {
    console.error('Failed to send email:', error);
    throw error;
  }
}

Strategia ponawiania

Dla błędów przejściowych (500, 502, 503, 504) implementuj exponential backoff. Dla 429 oraz 409 idempotency_request_in_progress czekaj tyle sekund, ile podaje nagłówek Retry-After:

import time
import random

def send_with_retry(payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = send_email(payload)
            return response
        except TransientError as e:
            if attempt == max_retries - 1:
                raise

            # Exponential backoff z jitter
            delay = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)

Rób:

  • Ponawiaj przy 429 i 409 idempotency_request_in_progress po Retry-After sekundach
  • Ponawiaj przy 500, 502, 503, 504 z exponential backoff, używając tego samego Idempotency-Key
  • Używaj exponential backoff
  • Dodaj losowy jitter by uniknąć thundering herd
  • Ustaw maksymalną liczbę ponowień

Nie rób:

  • Nie ponawiaj przy 400, 401, 403, 404, 409 conflict, 422 — nie zmienią się, dopóki nie zmienisz żądania lub stanu konta
  • Nie ponawiaj natychmiast bez opóźnienia
  • Nie ponawiaj w nieskończoność

Idempotencja

Dla bezpiecznego ponawiania używaj kluczy idempotencji:

curl -X POST https://api.mailingapi.com/v1/messages/send \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: unique-request-id-123" \
  -H "Content-Type: application/json" \
  -d '{...}'

Jeśli ponowisz żądanie z tym samym Idempotency-Key, otrzymasz oryginalną odpowiedź (z nagłówkiem Idempotent-Replayed: true) zamiast tworzyć duplikat. Generuj klucz raz na logiczne żądanie i używaj go przy każdym jego ponowieniu.

Błędy idempotencji:

Status error.code Znaczenie Ponawiać?
409 idempotency_request_in_progress Pierwsze żądanie z tym kluczem jest wciąż przetwarzane Tak, po Retry-After sekundach
422 idempotency_key_reused Klucz został już użyty z innym body żądania Nie — użyj nowego klucza
400 invalid_idempotency_key Klucz jest pusty lub dłuższy niż 255 znaków Nie

Pełne zasady: Przegląd API → Idempotencja.

Wskazówki do debugowania

  1. Przeczytaj code i details błędu — Kod jest stabilny i maszynowo czytelny; message to wyjaśnienie dla człowieka
  2. Sprawdź logi żądań — W dashboardzie pod Logi → Żądania API
  3. Waliduj lokalnie — Użyj /v1/messages/analyze by sprawdzić treść przed wysyłką

Uzyskanie pomocy

Jeśli utkniesz:

  • Przeszukaj API Reference (interaktywne, wymaga JavaScript) lub użyj specyfikacji OpenAPI 3 pod /api/openapi po szczegóły endpointów
  • Skontaktuj się support@mailingapi.com z:
    • Request ID (z nagłówków odpowiedzi)
    • Kodem błędu i wiadomością
    • Minimalnym przykładem reprodukcji

Następne kroki

Teraz rozumiesz jak obsługiwać błędy. Naucz się wysyłać emaile w szczegółach.

Wysyłanie emaili →