<!-- Source: https://docs.infraio.xyz/tr/api-reference/errors -->
<!-- Last updated: 2026-10-04 -->

# Hatalar

Her 4xx/5xx yanıtı aynı JSON zarfını taşır:

```json
{
  "code": 400,
  "message": "invalid_input",
  "details": [
    { "field": "items[0].unit_price", "message": "must be a positive decimal string" }
  ]
}
```

- `code` — **sayısal HTTP durumu** (`400`, `401`, `404`, …). Genel
  HTTP-katmanı işleme için kullanışlıdır, ancak dallanma mantığı için
  bunun yerine `message` üzerinde switch yapın — `code` örneğin
  `invalid_input` ile `payment_method_not_supported` (her ikisi de 400)
  arasında ayrım yapmaz.
- `message` — **lower-snake-case** sentinel adı (örn. `INVALID_INPUT`
  `"invalid_input"` olur). Sürümler arasında stabildir — bunun üzerinde
  switch yapın.
- `details` — doğrulama hatalarında doldurulur. İstemcinin hataları
  girdilere sabitlemesi için `{ field, message }` nesnelerinden oluşan
  dizi. Aksi takdirde atlanır.

> **Warning:**
>
> Hata gövdeleri bir trace ID veya timestamp içermez. Bir sorunu bildirmek
> için destek ekibine yanıt `Date` başlığını, `X-RateLimit-*` başlıklarını,
> satıcı ID'nizi, uç noktayı ve isteğin yaklaşık zamanını gönderin.

> **Note:**
>
> **Kimlik doğrulama hataları farklı bir şekil kullanır.** Yukarıdaki
> zarf, API'nin çoğu hata için döndürdüğü şeydir. İşlenmeden önce
> reddedilen istekler (bir `/b2b/v1/*` çağrısında eksik veya geçersiz
> `X-Signature`, bilinmeyen `X-Client-ID` veya eski `X-Timestamp`)
> `{ "error": "...", "message": "..." }` olarak geri gelir; burada `error`
> kaba bir slug'tır (`unauthorized` / `bad_request` /
> `service_unavailable`) ve `message` ayrıntıları taşır. Sayısal `code`
> ve `details` yoktur. Önce HTTP durumu üzerinde dallanın, ardından
> `message`'ı okuyun. Örnek (401):
>
> ```json
> { "error": "unauthorized", "message": "invalid signature" }
> ```

## HTTP durumu → tipik kodlar

| HTTP | Tipik `code` değerleri | Ne anlama gelir |
| --- | --- | --- |
| **400** | `INVALID_INPUT`, `MISSING_REQUIRED`, `INVALID_FORMAT`, `INVALID_LENGTH`, `INVALID_VALUE`, `PAYMENT_METHOD_NOT_SUPPORTED`, `AMOUNT_BELOW_MINIMUM` | Hatalı istek — `details`'e bakın |
| **401** | `INVALID_CREDENTIALS`, `INVALID_TOKEN`, `TOKEN_EXPIRED`, `INVALID_SIGNATURE` (B2B); `SESSION_EXPIRED` (yalnızca panel) | Auth başarısız — hatalı anahtar, süresi dolmuş timestamp, yanlış imza. Panel oturum açma kodları B2B entegrasyonlarıyla ilgili değildir. |
| **402** | `INSUFFICIENT_CREDIT` | Satıcının ön ödemeli bakiyesi tükendi — yeniden denemeden önce yükleyin |
| **403** | `FORBIDDEN`, `IP_BLOCKED` | Anahtar geçerli ama bu çağrı için scope/IP iznine sahip değil |
| **404** | `NOT_FOUND`, `RECORD_NOT_FOUND` | Kaynak yok (veya bu satıcı için yok) |
| **409** | `ALREADY_EXISTS` | Farklı bir gövde ile idempotency replay, ya da durum makinesi geçişi reddetti |
| **429** | `TOO_MANY_REQUESTS`, `TOO_MANY_ATTEMPTS` | Rate limit'e ulaşıldı; geri çekilin ve yeniden deneyin |
| **500** | `INTERNAL_SERVER_ERROR`, `EXTERNAL_SERVICE_ERROR` | Bizim hatamız; geri çekilmeyle yeniden denemek güvenli. |
| **503** | `SERVICE_UNAVAILABLE` | Bir alt bağımlılık çalışmıyor. Geri çekilme ile yeniden deneyin |

## Tam kod referansı

Görebileceğiniz `code` değerleri:

### Kimlik doğrulama (401)
- `INVALID_CREDENTIALS` — API anahtarı kombinasyonu reddedildi
- `INVALID_TOKEN` — token ayrıştırılamadı veya değiştirilmiş
- `TOKEN_EXPIRED` — token süresi doldu
- `SESSION_EXPIRED` — panel oturumunun süresi doldu
- `INVALID_SIGNATURE` — B2B / webhook çağrılarında HMAC imza uyumsuzluğu

### Yetkilendirme (403)
- `FORBIDDEN` — doğrulandınız, ancak bu eylemi gerçekleştirme izniniz yok
- `IP_BLOCKED` — bu IP adresinden gelen istekler engellendi

### Bulunamadı (404)
- `NOT_FOUND` — genel
- `RECORD_NOT_FOUND` — verilen ID için satır eksik

### Çakışma (409)
- `ALREADY_EXISTS` — genel

### Doğrulama (400)
- `INVALID_INPUT` — genel; `details`'i kontrol edin
- `MISSING_REQUIRED` — gerekli bir alan eksik
- `INVALID_FORMAT` — değer beklenen formatla eşleşmedi (örn. UUID, URL, e-posta)
- `INVALID_LENGTH` — değer çok kısa veya çok uzun
- `INVALID_VALUE` — değer izin verilen enum/aralığın dışında
- `PAYMENT_METHOD_NOT_SUPPORTED` — provider/varlık kombinasyonu satıcı için etkin değil
- `AMOUNT_BELOW_MINIMUM` — sipariş tutarı ağ başına veya env-seviyesi zemininin altında. Yanıtın `details.floor_usd` alanı yapılandırılmış zemini (USD) taşır, böylece onu doğrudan yüzeye çıkarabilirsiniz; `message` metni de bunu belirtir.
- `INSUFFICIENT_BALANCE` — alıcının cüzdanı, transferi karşılamak için yeterli ödeme varlığını tutmuyor.
- `INSUFFICIENT_GAS` — alıcının cüzdanında transferi yaymak için yerel gas eksik.

### Ödeme / faturalama (402)
- `INSUFFICIENT_CREDIT` — satıcı ön ödemeli bakiyesi ağ ücretini (gas) / platform ücretini karşılayamaz. Panel üzerinden yükleyin, ardından yeniden deneyin

### Rate limit (429)
- `TOO_MANY_REQUESTS` — IP rate limit'i aşıldı
- `TOO_MANY_ATTEMPTS` — aynı kaynak üzerinde (örn. OTP) tekrar eden başarısız denemeler bir throttle'ı tetikledi

### Sunucu hataları (500)
- `EXTERNAL_SERVICE_ERROR` — bir üçüncü taraf provider başarısız oldu
- `INTERNAL_SERVER_ERROR` — beklenmedik hata; yanıt `Date` başlığı ve `X-RateLimit-*` başlıklarıyla destek ekibine ulaşın

### Kullanılabilirlik (503)
- `SERVICE_UNAVAILABLE` — servis geçici olarak kullanılamıyor; geri çekilmeyle yeniden deneyin

## Doğrulama hataları (400)

Sorun hatalı biçimlendirilmiş bir istek gövdesi olduğunda, `details` bir
dizidir, böylece hataları alanlara geri eşleyebilirsiniz:

```json
{
  "code": 400,
  "message": "invalid_input",
  "details": [
    { "field": "items[0].unit_price", "message": "must be a positive decimal string" },
    { "field": "success_url", "message": "must be a valid https URL" }
  ]
}
```

## Auth hataları (401)

`INVALID_SIGNATURE`'ın üç yaygın nedeni vardır:

- Yanlış secret anahtar (env var'ı yeniden kontrol edin)
- Timestamp sapması > 5 dk (NTP senkronize edin)
- Yanlış kanonik dize (en sık: `\n` ayraçlarını unutmak veya
  ayrıştırılıp-sonra-yeniden-stringleştirilmiş, gönderdiğinizden farklı
  bir gövdeyi imzalamak)

Tam imzalama algoritması için
[Kimlik doğrulama](https://docs.infraio.xyz/tr/api-reference/authentication) sayfasına bakın.

## Rate limit'ler (429)

| Yüzey | Limit |
| --- | --- |
| Tüm API rotaları (`/b2b/v1/*` dahil) | IP adresi başına — **500 req/dk**, paylaşımlı kova. Satıcı başına değil. |
| Public checkout (`/checkout/*`) | Daha sıkı alt kova — IP başına **20 req/dk** |

`X-RateLimit-Limit` ve `X-RateLimit-Remaining`, rate limit'e takılan her
yanıta eklenir, yalnızca başarılı olanlara değil. Bunları IP'niz için
canlı bütçe olarak değerlendirin.

Rate-limit'li yanıtlar bir `Retry-After` başlığı içerir (pencerenin
sıfırlanmasına kalan saniye) — buna uyun. Yedek olarak, jitter ile geri
çekilin — 1s temel + 30s'ye üstel artan bekleme süresi.

> **Note:**
>
> Rate limit'ler değişebilir. Meşru trafikle bunlara ulaşıyorsanız
> (örn. büyük bir tarihsel aralığı mutabık kılıyorsanız), destek ekibiyle
> iletişime geçin.

## Yetersiz kredi (402)

`INSUFFICIENT_CREDIT` (HTTP **402 Payment Required**), ön ödemeli
bakiyenizin, gerçekleştirmeye çalıştığınız işlem için ağ ücretini (gas) ve
platform ücretini karşılayamadığı anlamına gelir; tipik olarak bir kripto
ödemesinin tahsil edilmesi veya ağ ücreti karşılanan bir zincir üstü eylem.
Satıcı panelinden (**Faturalama → Kredi ekle**) yükleyin, ardından işlemi
yeniden deneyin. Devam etmekte olan işlemler bakiye yüklendiğinde otomatik
olarak sürer.

## Sunucu hataları (5xx)

Bir 500, isteği işleyemediğimiz anlamına gelir. Geri çekilme ile yeniden
deneyin — `idempotency_key`'iniz, orijinal istek kısmen başarılı olmuş
olsa bile çift ücretlendirme yapmamanızı sağlar.

Yeniden denemeler bir dakika içinde kurtarılmazsa, alıcıya genel bir
"ödeme geçici olarak kullanılamıyor" gösterin ve başarısız uç noktayı,
satıcı ID'nizi, yanıt `Date` başlığını ve `X-RateLimit-*` değerlerini ve
yaklaşık istek zamanını destek ekibine iletin — bu, isteği bulmamız
için yeterlidir.

## Webhook teslim hataları

Webhook teslimleri ayrı bir başarısızlık kanalıdır — API hatası olarak
yüzeye çıkmazlar çünkü sunucunuz çağrı yapan taraf değildir. Bir teslim
2xx-olmayan bir yanıt döndürdüğünde (veya zaman aşımına uğradığında),
üstel artan bekleme süresi ile 0s, 1dk, 5dk, 15dk, 1s, 6s aralıklarında
yeniden denenir (toplam altı deneme, [Webhook'lar → Genel bakış](https://docs.infraio.xyz/tr/webhooks/overview)
ile aynı program). Tam teslim başına geçmiş, panelin **Geliştiriciler →
Webhook'lar → [uç nokta] → Teslim günlüğü** altında görünür. Altıncı
denemeden sonra teslim panelde "Başarısız" olarak işaretlenir ve sunucunuz
sağlıklı olduğunda manuel olarak yeniden oynatabilirsiniz.
