Hatalar
Her 4xx/5xx yanıtı aynı JSON zarfını taşır:
{
"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 yerinemessageüzerinde switch yapın —codeörneğininvalid_inputilepayment_method_not_supported(her ikisi de 400) arasında ayrım yapmaz.message— dahilierrors.gosabitinden türetilen lower-snake-case sentinel adı (örn.INVALID_INPUT → "invalid_input"). 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.
Şu anda gövdede trace_id veya timestamp döndürmüyoruz. Bu sayfanın
önceki taslakları her ikisini de vaat ediyordu — bu özlemdi. Bir
sunucu logunu bir istekle ilişkilendirmeniz gerekirse, yanıt Date
başlığını ve geçit tarafı rate-limit başlıklarını (X-RateLimit-*)
yakalayın ve bunları bir destek talebinde belirtin.
Geçit-kenarı reddetmeleri farklı bir şekil kullanır. Yukarıdaki
zarf, backend servislerinin yaydığı şeydir. Bir servise ulaşmadan
önce geçidde reddedilen istekler — bir /b2b/v1/* çağrısında
eksik/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. Bu yüzden bir doğrulayıcı önce HTTP durumu
üzerinde dallanmalı, ardından message’ı okumalı ve code/details’i
yalnızca istek geçidi geçtikten sonra mevcut olarak değerlendirmelidir.
Örnek geçit gövdesi (401):
{ "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, INVALID_USER_STATUS, INVALID_USER_ROLE, PAYMENT_METHOD_NOT_SUPPORTED, AMOUNT_BELOW_MINIMUM | Hatalı istek — details’e bakın |
| 401 | INVALID_CREDENTIALS, INVALID_TOKEN, TOKEN_EXPIRED, INVALID_SIGNATURE (B2B); INVALID_OTP, OTP_EXPIRED, SESSION_EXPIRED (yalnızca panel / JWT) | Auth başarısız — hatalı anahtar, süresi dolmuş timestamp, yanlış imza. OTP/SESSION_EXPIRED kodları yalnızca panel-JWT rotalarında (/payment/v1/*) yüzeye çıkar; saf B2B entegrasyonları bunları görmez. |
| 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, USER_NOT_FOUND, SESSION_NOT_FOUND | Kaynak yok (veya bu satıcı için yok) |
| 409 | ALREADY_EXISTS, USER_ALREADY_EXISTS, SESSION_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, DATABASE_CONNECTION_ERROR, DATABASE_QUERY_ERROR, DATABASE_TRANSACTION_ERROR, REDIS_CONNECTION_ERROR, REDIS_OPERATION_ERROR, EXTERNAL_SERVICE_ERROR | Bizim hatamız; geri çekilmeyle yeniden denemek güvenli. (TWILIO_SERVICE_ERROR / SENDGRID_SERVICE_ERROR gibi provider’a özgü kodlar dahili olarak vardır ama yalnızca panel tarafı bildirim akışlarında yüzeye çıkar, B2B uç noktalarında değil.) |
| 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ğerlerinin tam kümesi
(payment-service/pkg/errors/errors.go ile eşleşir):
Auth ve oturumlar (401)
INVALID_CREDENTIALS— kullanıcı adı/şifre veya API anahtarı kombinasyonu reddedildiINVALID_TOKEN— JWT/oturum token’ı ayrıştırılamadı veya değiştirilmişTOKEN_EXPIRED— JWTexp’i geçtiINVALID_OTP— OTP eşleşmiyorOTP_EXPIRED— OTP tolerans penceresi öncesinde verildiSESSION_EXPIRED— panel oturumu süresi dolduINVALID_SIGNATURE— B2B / webhook çağrılarında HMAC imza uyumsuzluğu
Yetkilendirme (403)
FORBIDDEN— doğrulandı ama rol/scope/satıcı sınırı eylemi engelliyorIP_BLOCKED— IP suistimal listesinde
Bulunamadı (404)
NOT_FOUND— genelRECORD_NOT_FOUND— verilen ID için satır eksikUSER_NOT_FOUND— kullanıcı araması başarısızSESSION_NOT_FOUND— panel oturum id’si tanınmıyor
Çakışma (409)
ALREADY_EXISTS— genelUSER_ALREADY_EXISTS— kayıt benzersizlik kısıtlamasına çarptıSESSION_ALREADY_EXISTS— yinelenen oturum eklemesi
Doğrulama (400)
INVALID_INPUT— genel;details’i kontrol edinMISSING_REQUIRED— gerekli bir alan eksikINVALID_FORMAT— değer beklenen formatla eşleşmedi (örn. UUID, URL, e-posta)INVALID_LENGTH— değer çok kısa veya çok uzunINVALID_VALUE— değer izin verilen enum/aralığın dışındaINVALID_USER_STATUS— kullanıcı eylemi yasaklayan bir durumdaINVALID_USER_ROLE— rol eylem için izinden yoksunPAYMENT_METHOD_NOT_SUPPORTED— provider/varlık kombinasyonu satıcı için etkin değilAMOUNT_BELOW_MINIMUM— sipariş tutarı ağ başına veya env-seviyesi zemininin altında. Yanıtındetails.floor_usdalanı yapılandırılmış zemini (USD) taşır, böylece onu doğrudan yüzeye çıkarabilirsiniz;messagemetni 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 gas / platform ücretini karşılayamaz. Panel üzerinden yükleyin, ardından yeniden deneyin
Rate limit (429)
TOO_MANY_REQUESTS— geçit IP rate-limitTOO_MANY_ATTEMPTS— aynı kaynak üzerinde (örn. OTP) tekrar eden başarısız denemeler bir throttle’ı tetikledi
Depolama / altyapı (500)
DATABASE_CONNECTION_ERROR— DB’ye ulaşılamadıDATABASE_QUERY_ERROR— query plan runtime’da başarısız olduDATABASE_TRANSACTION_ERROR— commit/rollback başarısız olduREDIS_CONNECTION_ERROR— Redis’e ulaşılamadıREDIS_OPERATION_ERROR— Redis komutu başarısız olduEXTERNAL_SERVICE_ERROR— genel üçüncü taraf hatası (aşağıda kovaya alınmamış provider)TWILIO_SERVICE_ERROR— Twilio SMS / Verify çağrısı başarısız olduSENDGRID_SERVICE_ERROR— SendGrid posta gönderimi başarısız olduINTERNAL_SERVER_ERROR— beklenmedik fall-through; yanıtDatebaşlığı +X-RateLimit-*’ı yakalayın ve ulaşın
Kullanılabilirlik (503)
SERVICE_UNAVAILABLE— kritik bir alt bağımlılık sağlıksız raporluyor; geri çekilme + yeniden deneme
Doğrulama hataları (400)
Sorun hatalı biçimlendirilmiş bir istek gövdesi olduğunda, details bir
dizidir, böylece hataları alanlara geri eşleyebilirsiniz:
{
"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 üç farklı arıza modunu kapsar — onları ayırt etmenin
tek yolu ikileştirmektir:
- Yanlış secret anahtar (env var’ı yeniden kontrol edin)
- Timestamp sapması > 5 dk (NTP senkronize edin)
- Yanlış kanonik dize (en sık:
\nayraç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 sayfasına bakın.
Rate limit’ler (429)
| Yüzey | Limit |
|---|---|
Her geçit rotası (/b2b/v1/* dahil) | Geçidde IP 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, her geçit-rate-limitli
yanıtta yayılır (yalnızca başarılarda 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.
Rate limit’ler değişebilir. Onlara meşru bir şekilde ulaşıyorsanız (örn. büyük bir tarihsel aralığı mutabık kılıyorsanız), ulaşın — toplu uç noktalar yol haritasında.
Yetersiz kredi (402)
INSUFFICIENT_CREDIT (HTTP 402 Payment Required), satıcının ön
ödemeli bakiyesinin, gerçekleştirmeye çalıştığınız işlem için bir sonraki
gas-ve-platform ücretini karşılayamadığı anlamına gelir — tipik olarak
bir kripto ödemesi tahsil etme veya gas-sponsorlu bir zincir üstü eylem
yürütme. Satıcı panelinden (Faturalama → Kredi ekle) yükleyin,
ardından işlemi yeniden deneyin; uçuştaki iş bekler ve bakiye temizlenir
temizlenmez otomatik olarak devam eder.
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, loglarımızda ilgili
isteğe geçmemiz 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), 0s, 1dk, 5dk, 15dk, 1s, 6s aralıklarında üstel artan bekleme süresi ile yeniden denemek üzere kuyruğa alınır (toplam altı deneme — bkz. Webhook’lar → Genel bakış 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 dead-letter’a gönderilir — panel sunucunuz sağlıklı olduğunda manuel olarak yeniden oynatabileceğiniz bir “Başarısız” rozeti gösterir.