Skip to main content
Payven hata yanıtları RFC 9457 — Problem Details for HTTP APIs standardına uyar. Tüm hata response’larının body’leri application/problem+json MIME tipindedir; HTTP durum kodu kategoriyi, gövdedeki code alanı ise hatanın programatik tipini belirtir.

Hata yanıt formatı

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
X-Correlation-Id: 9f1c8e76-2a3b-4f12-9c8d-12cb24a8a8a8
{
  "type":           "https://docs.payven.com.tr/errors/refund_exceeds_original",
  "title":          "İade tutarı orijinali aşıyor",
  "status":         422,
  "code":           "refund_exceeds_original",
  "detail":         "Toplam iade tutarı orijinal tutarı (15000 kuruş) aşamaz.",
  "instance":      "/api/v1/payments/8e3f5c12-.../refund",
  "correlation_id": "9f1c8e76-2a3b-4f12-9c8d-12cb24a8a8a8"
}
AlanZorunlulukAçıklama
typeZorunluHata tipinin kanonik URI’si. Aynı zamanda dokümantasyon linki olarak çalışır.
titleZorunluKısa, insan-okur başlık (Türkçe).
statusZorunluHTTP status kodu (header ile aynı değer, gövdede yinelenir).
codeZorunluProgramatik hata kodu (snake_case). type URI’sinin son segmenti.
detailOpsiyonelBu özel duruma ilişkin açıklayıcı mesaj.
instanceOpsiyonelHatanın oluştuğu kaynak yolu.
correlation_idOpsiyonelİstek zinciri kimliği. Response header’ı X-Correlation-Id ile aynı. Destek talebinde paylaşın.

HTTP kategorileri

HTTPKategoriÖrnek codeRetry
400 Bad RequestGeçersiz JSON, eksik alan, format hatasıbad_request, invalid_jsonDüzeltmeden tekrarlamayın
401 UnauthorizedToken yok, geçersiz, expireunauthorized, invalid_token, token_expiredYeniden token alın
403 ForbiddenYetki yok, lisans yok, merchant pasifforbidden, merchant_inactive, product_not_licensedHayır — yetki/lisans çözülmeden tekrar göndermeyin
404 Not FoundKaynak bulunamadıresource_not_found, payment_not_foundHayır
409 ConflictIdempotency çakışması, durum geçişi geçersizconflict, idempotency_key_in_use, invalid_state_transitionHayır
422 Unprocessable Entityİş kuralı veya validasyon ihlalivalidation_failed, refund_exceeds_original, bank_declinedHayır — istek/iş kuralı düzeltilmeden retry yapmayın
429 Too Many RequestsRate limit aşıldı (Retry-After header gönderilir)rate_limit_exceededBackoff
500/502/503Sunucu / bağlantı hatasıinternal_server_error, bad_gateway, service_unavailableBackoff
Network timeoutAğ veya gateway timeoutIdempotency-Key ile
Banka reddi de bir hata yanıtıdır. Gateway’e ulaşmış ama banka tarafında reddedilen ödeme 422 Unprocessable Entity + application/problem+json ile döner; gövdede code: "bank_declined" ve banka ham yanıt kodu (provider_error_code, örn. "51" — yetersiz bakiye) yer alır. Sonuç değerlendirmesini yalnız HTTP durum kodu üzerinden yapın.

Yaygın hata kodları

Kimlik doğrulama / yetki

codeHTTPAnlam
unauthorized401Authorization header eksik
invalid_token401Access token geçersiz veya kurcalanmış
token_expired401Access token süresi doldu — refresh edin
invalid_credentials401client_id / client_secret yanlış
invalid_refresh_token401Refresh token expire / revoke edilmiş
realm_not_found404Auth endpoint’inde {slug} geçersiz
realm_suspended403Tenant askıya alınmış
forbidden403Bu rol bu kaynağı göremez
merchant_inactive403Belirtilen merchant pasif
merchant_not_found403X-Merchant-Id / X-External-Merchant-Id çözümlenemedi
product_not_licensed403Modül planınızda etkin değil
ip_not_allowed403İstek IP’si izin listesinde değil

İstek formatı / validasyon

codeHTTPAnlam
bad_request400Genel istek hatası
invalid_json400Gövde geçersiz JSON
validation_failed422Validasyon kuralı ihlali — errors[] ile alan listesi
invalid_amount422Tutar pozitif değil veya minimum altında
invalid_currency422Para birimi desteklenmiyor (TRY dışı için kapalı)
invalid_card422Kart numarası Luhn checksum’ı geçmiyor
invalid_expiry422Son kullanma tarihi geçmiş veya format yanlış
invalid_installment422Taksit sayısı bu BIN için desteklenmiyor
invalid_iban422IBAN checksum’ı geçmiyor
Validasyon hatalarında alan-bazlı detay errors[] array’inde döner:
{
  "type":   "https://docs.payven.com.tr/errors/validation_failed",
  "title":  "Validasyon hatası",
  "status": 422,
  "code":   "validation_failed",
  "detail": "1 alan geçersiz",
  "errors": [
    {
      "field":   "amount.amount",
      "code":    "below_minimum",
      "message": "Tutar 100 kuruşun altında olamaz."
    }
  ]
}

Ödeme / işlem kuralları

codeHTTPAnlam
payment_not_found404İşlem bulunamadı
payment_already_refunded422Tüm tutar zaten iade edilmiş
payment_not_refundable422Mevcut durumda iade yapılamaz
refund_exceeds_original422İade tutarı orijinali aşıyor
void_not_allowed_after_settlement422Mutabakat sonrası iptal yapılamaz
capture_amount_exceeds_authorization422Çekim tutarı ön provizyonu aşıyor
invalid_state_transition409Durum geçişi izin verilmiyor (örn. FailedCaptured)
duplicate_external_id409Aynı external_id ile başka işlem zaten var

Yönlendirme ve banka

codeHTTPAnlam
routing_no_match422Hiçbir konnektör koşullara uymadı
connector_unavailable503Hedef konnektör geçici olarak devre dışı (circuit breaker açık)
bank_declined422Banka işlemi reddetti — provider_error_code bankadan dönen kod
bank_timeout504Banka yanıt vermedi (Smart Retry tetiklenmiş olabilir)
fraud_blocked422Fraud kuralı tetiklendi (fraud.decision: "block")
fraud_review_required422Manuel inceleme bekliyor

Idempotency / rate limit

codeHTTPAnlam
idempotency_key_in_use409Aynı Idempotency-Key farklı body için kullanılmış
rate_limit_exceeded429İstek limiti aşıldı (Retry-After header’ına uyun)
Banka yanıt kodlarının ve konnektör hata mesajlarının tam listesi: Sanal POS → Hata Kodları.

Retry stratejisi

Sadece geçici hatalar için retry uygun: 429, 5xx, network timeout. Idempotent olmayan işlemleri retry ederken mutlaka aynı Idempotency-Key kullanın — yoksa aynı işlem birden fazla yapılır. Önerilen pattern: exponential backoff + jitter.
1. deneme: hemen
2. deneme: ~1 sn sonra
3. deneme: ~2 sn sonra
4. deneme: ~4 sn sonra
5. deneme: ~8 sn sonra (üst limit)
async Task<HttpResponseMessage> SendWithRetryAsync(
    Func<HttpRequestMessage> requestFactory,
    int maxAttempts = 5,
    CancellationToken ct = default)
{
    var rng = new Random();
    for (int attempt = 0; ; attempt++)
    {
        var response = await _http.SendAsync(requestFactory(), ct);
        if (response.IsSuccessStatusCode) return response;

        var status = (int)response.StatusCode;
        var retryable = status == 429 || status >= 500;
        if (!retryable || attempt >= maxAttempts - 1) return response;

        var delaySec = Math.Pow(2, attempt);
        if (response.Headers.RetryAfter?.Delta is { } ra) delaySec = ra.TotalSeconds;
        var jitter = rng.NextDouble() * 0.5;
        await Task.Delay(TimeSpan.FromSeconds(delaySec + jitter), ct);
    }
}
Tekrar denerken aynı Idempotency-Key ile gönderin. Aynı işlemin iki kez oluşmasını engeller. Bkz. Idempotency.

Müşteriye gösterme

detail alanı son kullanıcıya gösterilebilir nitelikte yazılır. Yine de hassas durumlarda (fraud, fraud-review, banka tarafı reddi) genel bir mesajla geçiştirmek daha güvenlidir:
function userMessage(problem) {
  switch (problem.code) {
    case "validation_failed":
      return problem.detail;
    case "bank_declined":
    case "fraud_blocked":
    case "fraud_review_required":
      return "İşleminiz onaylanmadı. Farklı bir kart deneyebilirsiniz.";
    case "rate_limit_exceeded":
      return "Şu an çok fazla istek alıyoruz. Lütfen kısa bir süre sonra tekrar deneyin.";
    default:
      return "İşleminiz gerçekleştirilemedi. Lütfen tekrar deneyin.";
  }
}

Destek talebi açarken

Her hata yanıtında dönen correlation_id değerini paylaşın — log zincirini saniyeler içinde bulabiliriz. Response header’ındaki X-Correlation-Id ile gövdedeki correlation_id aynı değerdir.
Konu:   Refund 422 — refund_exceeds_original
Detay:  correlation_id: 9f1c8e76-2a3b-4f12-9c8d-12cb24a8a8a8
        instance:      /api/v1/payments/8e3f5c12-.../refund
        zaman:         2026-05-05T14:23:11+03:00