Hata kodları
Hata yanıtının biçimi ve API’nin döndürebileceği dokuz hata kodu. Kod kümesi kapalıdır: bunların dışında bir kod görmezsiniz. Önce hata zarfını, sonra kodun ne yapmanız gerektiğini söyleyen tabloyu okuyun.
Hata zarfı
API’nin ürettiği her hata yanıtı aynı JSON zarfını taşır:
| Alan | Anlamı |
|---|---|
error | Makine için hata kodu. Kodunuzda hata durumlarını bu alana göre ayırın. |
message | İnsan için Türkçe açıklama. Metni sürümler arasında değişebilir; ayrıştırmayın ve karşılaştırmayın. |
details | Yalnız söyleyecek bir şey varsa gelir. Doğrulama hatalarında details.field reddedilen alanın istekteki adıdır; 500 yanıtında details.request_id bulunur; imza başlıkları bozuk bir istekte 401 yanıtı details.hint taşır. |
HTTP/1.1 400 Bad Request
X-Error-Code: validation_failed
X-Request-Id: 0192e8a1-7c3f-7d2e-b5a4-3f6c9d8e1a20
{
"error": "validation_failed",
"message": "Stok kodu gerekli",
"details": { "field": "code" }
}Kod aynı zamanda X-Error-Code yanıt başlığında bulunur; gövdeyi okumadan günlüğe yazabilirsiniz. Her yanıt (başarılı olsun olmasın) bir X-Request-Id başlığı taşır. 500 yanıtında bu değer details.request_id alanında da gelir; destek talebine yazacağınız tek değer budur.
{
"error": "internal_error",
"message": "Beklenmeyen bir hata oluştu",
"details": { "request_id": "0192e8a1-7c3f-7d2e-b5a4-3f6c9d8e1a20" }
}Tek istisna ağ katmanıdır: 502, 503 ve 504 yanıtlarını API’nin kendisi üretmez, gövdeleri JSON olmayabilir. Gövdeyi çözmeden önce Content-Type başlığına bakın.
Kod kümesi
API içeride bundan çok daha ayrıntılı hata kodları kullanır; dışarıya bu dokuz kod verilir. Çakışma ve durum hataları conflict ile invalid_state altında toplanır. Kümeye yeni bir kod eklemek sözleşme değişikliğidir ve değişiklik günlüğünde duyurulur.
| Kod | HTTP | Anlamı | Ne yapmalı |
|---|---|---|---|
validation_failed | 400 | İstek gövdesi ya da sorgu parametresi doğrulamadan geçemedi. | İsteği aynen yeniden göndermeyin. details.field (varsa) reddedilen alanı söyler; onu düzeltip gönderin. |
unauthorized | 401 | Anahtar bulunamadı, kapatılmış (pasif) ya da süresi dolmuş; ya da imza veya zaman damgası doğrulanamadı. Başlıkların biçimi doğruysa bu dört durum aynı genel yanıtı alır; biçim bozuksa yanıt details.hint ile neyin bozuk olduğunu söyler. | details.hint varsa önce ona bakın. Yoksa anahtarın panelde aktif olduğunu, kanonik dizenizin test vektörüyle tuttuğunu ve sunucu saatinizin ±5 dakika içinde olduğunu doğrulayın. |
forbidden | 403 | Anahtar geçerli ama işlem reddedildi: operasyonun istediği kapsam anahtarda yok. Fatura gönderiminde hesap belge kesmeye kapalıysa (firma pasif ya da deneme süresi dolmuş) aynı kod döner; message nedeni söyler. | Kapsam eksikse yanıt eksik kapsam kodunu söylemez. Anahtarın kapsamı sonradan değiştirilemez; gereken kapsamla yeni bir anahtar üretin. Hesap kısıtıysa çözüm anahtarda değil, hesabın yeniden etkinleştirilmesindedir. |
not_found | 404 | Kaynak yok ya da başka bir firmaya ait; yol ya da yöntem /v1 altında tanımlı değilse de bu kod döner. Mesaj kaynağın türünü söyler, id’sini değil. | Yeniden denemeyin; yolu, yöntemi, id değerini ve anahtarın firmasını doğrulayın. |
conflict | 409 | Kaydın bugünkü durumu isteği kabul etmiyor (örneğin zaten gönderilmiş bir taslağı yeniden göndermek) ya da benzersiz olması gereken bir değer (VKN, ürün kodu, kategori adı) zaten kullanılıyor. | Kaydı geri okuyup güncel durumuna göre karar verin; aynı isteği olduğu gibi yeniden göndermek aynı yanıtı verir. |
invalid_state | 422 | İstek biçimsel olarak doğru ama iş kuralı bu işleme izin vermiyor (belgenin durumu, zaman penceresi, firma yapılandırması; abonelik ödemesinin gecikmesi, kontör eşiği ve aşım tavanı da buradadır). | İsteği aynen yeniden göndermeyin; message hangi kuralın engellediğini söyler. Önce engeli giderin. |
idempotency_key_reuse | 422 | Aynı Idempotency-Key başka bir istek için (farklı uç ya da farklı gövde) kullanılmış. | Her mantıksal işlem için yeni bir anahtar üretin (örneğin UUID). Aynı işlemi yeniden denerken aynı anahtarı ve aynı gövdeyi gönderin. |
rate_limited | 429 | Oran ya da eşzamanlılık tavanı aşıldı; hangi kova olduğu X-RateLimit-Resource başlığındadır (anahtar ya da firma toplamı, genel ya da indirme). | Retry-After başlığındaki saniye kadar bekleyip yeniden deneyin. Beklemeden art arda denemek sonucu değiştirmez, istekler 429 almaya devam eder. firm: ile başlayan kova firmanın bütün anahtarlarının ortak kotasıdır; firm:download-concurrency aynı anda çok fazla indirme açıldığını söyler. |
internal_error | 500 | Sunucu tarafında beklenmeyen hata. | Okuma isteklerini üstel geri çekilmeyle yeniden deneyin. Yazma isteklerinde yeniden göndermeden önce kaydın oluşup oluşmadığını okuyun: istek sunucuda işlenmiş olabilir ve hemen yeniden göndermek çift kayıt açabilir (gönderim ucu istisnadır: aynı Idempotency-Key ile yeniden gönderilebilir). Destek kaydında details.request_id değerini paylaşın. |
400, 409 ve 422 nasıl ayrılır
Üçü de “isteğiniz kabul edilmedi” der ama nedenleri farklıdır:
- 400
validation_failed: isteğin kendisi geçersizdir. Örnekler: kontrol basamağı tutmayantax_number, kümede olmayan birscenario, 2 MiB’ı aşan gövde.details.fieldçoğunlukla alanı gösterir. - 409
conflict: istek geçerlidir ama kaydın o anki durumu ya da başka bir kayıt işlemi engeller. Örnekler: gönderilmiş bir faturayı yeniden göndermek ya da aynıcodeile ikinci bir stok kartı açmak. - 422
invalid_state: istek geçerlidir ama bir iş kuralı izin vermez. Örnekler: bugünden ileri tarihli fatura, TRY dışındaki belgedeexchange_rateeksikliği, ödeme gecikmesi ya da kontör eşiği. Gönderim öncesi kapıların çoğu bu koddur; istisnalar firma ve deneme durumunu bildiren403 forbiddenile belgenin GİB kurallarını bildiren400 validation_failedyanıtlarıdır. Hangisi olursa olsun taslak yerinde kalır, düzeltip yeniden gönderebilirsiniz. Hangi önkoşulun hangi koda düştüğü Fatura kesme akışındadır.
401 yanıtı
Üç imza başlığından biri eksikse ya da biçimi bozuksa yanıt neyin bozuk olduğunu details.hint ile söyler (error ve message değişmez):
X-Api-Key,X-Api-TimestampveX-Api-Signaturebaşlıklarından biri eksik.X-Api-Keydeğeriysk_ile başlamıyor: büyük olasılıkla secret ya da başka bir değer yapıştırılmış.X-Api-Timestamptamsayı değil (Unix saniyesi olmalı).X-Api-Signature64 karakterlik hex değil. Secret bu başlığa yazılmaz; imza, secret ile hesaplanır.
{
"error": "unauthorized",
"message": "API anahtarı doğrulanamadı",
"details": { "hint": "X-Api-Timestamp Unix saniyesi (tamsayı) olmalı." }
}Başlıkların biçimi doğruysa 401 nedenini söylemez: anahtarın bulunamaması, pasif olması, süresinin dolması ve imzanın ya da zaman damgasının yanlış olması (yanlış secret, saat sapması dahil) aynı yanıtı alır ve details hiç gelmez. Ayrımı yayımlamak, anahtar deneyen birine hangi adımda olduğunu öğretirdi. Yanıtta ipucu yoksa sırayla şunları kontrol edin:
X-Api-Keybaşlığındaki değer panelde gösterilen anahtarla aynı mı? Anahtar kapatılmış olabilir: panelde anahtar kartındaki Servis aktif düğmesi kapalıysa her istek 401 alır. Kapatan firma yetkilisi, iş ortağı ya da YouSoft olabilir; ayrıntı için Anahtar kapatma bölümüne bakın.- İmzayı doğru güvenlik anahtarıyla (secret) üretiyor musunuz? Yeni güvenlik anahtarı üretildiyse önceki değer yalnız 24 saat daha geçerlidir; süre dolunca onunla imzalanan her istek 401 alır.
X-Api-TimestampUNIX saniyesi mi (milisaniye değil) ve sunucu saatiniz ±5 dakika içinde mi?- İmzaladığınız yol ve sorgu dizesi, telden giden dizeyle birebir aynı mı? Süzgeç parantezleri kodlanmamalıdır.
- Test vektörünü çalıştırın: vektör tutuyorsa sorun imza algoritmasında değildir.
Anahtarın başkasının eline geçtiğinden şüpheleniyorsanız önce kontrol listesini değil Anahtar sızdıysa adımlarını izleyin. 401 yanıtı oran sınırı başlıklarını (X-RateLimit-*) taşımaz.
{
"error": "unauthorized",
"message": "API anahtarı doğrulanamadı"
}