Ana içeriğe geç
YouSoftGeliştirici Portalı
Dokümanlar

Fatura kesme akışı

Bu sayfa bir satış faturasını API ile baştan sona kesmenin yolunu anlatır: cari kartı hazırlayın, taslağı yazın, gönderin ve sonucu izleyin. Faturayı kendi yazılımından kesecek geliştiriciye yöneliktir; gönderim önkoşulları, numara kuralları, faturaları listeleme, XML ve PDF indirme, iptal ve gelen faturalar da burada.

Akış bir bakışta

Fatura kesmek beş istektir. Her adım aşağıda ayrıca anlatılır; imza ayrıntıları için İmzalama sayfasına bakın.

AdımUç ve gereken kapsamYanıt
1. Cari kartı oluşturunPOST /v1/contacts
Kart.MusteriTedarikciDuzenleyebilir
201, cari kart
2. Alıcı e-Fatura mükellefi mi, bakınGET /v1/e-invoice-inboxes/{tax_number}
Diger.EBelgeMukellefBilgileriIzleyebilir
200, mükellefiyet kaydı
3. Taslağı yazınPOST /v1/invoices
Fatura.SatisFaturasiDuzenleyebilir
201, taslak (id burada gelir)
4. Gönderime alınPOST /v1/invoices/{id}/send
EFatura.TaslaktanGonderimYapabilir
202, yalnız invoice_id
5. Durumu izleyinGET /v1/invoices/{id}
EFatura.GidenKutusuIzleyebilir
200, status alanı

1. Cari kartı hazırlayın

Fatura bir cari karta kesilir: taslak gövdesinde contact_id zorunludur. Alıcınız için kart yoksa oluşturun. Tüzel kişide zorunlu alan yalnız title’dır, ama gönderim için aşağıdaki bilgiler de gerekir. Örnekteki değerler uydurmadır.

JSON, POST /v1/contacts
{
  "title": "Örnek Ticaret Ltd. Şti.",
  "type": "MUSTERI",
  "person_type": "TUZEL",
  "tax_number": "1234567890",
  "tax_office": "Kadıköy",
  "address": {
    "line": "Örnek Mah. Deneme Sok. No: 1",
    "district": "Kadıköy",
    "city": "İstanbul"
  }
}
  • tax_number 10 haneli VKN, national_id 11 haneli TCKN olmalı ve kontrol basamağı tutmalıdır; tutmayan değer 400 validation_failed alır. İstisnalar: nihai tüketici kimliği 11111111111 ve yurt dışındaki alıcının VKN’si 2222222222.
  • Gerçek kişi (person_type: GERCEK ya da 11 haneli national_id) kartta first_name ve last_name ayrı ve zorunludur; biri eksikse 400 validation_failed (details.field first_name ya da last_name). title bu ikisinden türer, gönderdiğiniz title kullanılmaz. Faturada alıcının adı ve soyadı bu alanlardan yazılır; ikisi boş eski bir gerçek kişi kartına kesilen fatura gönderimde 422 invalid_state alır. Nihai tüketici ve yurt dışı alıcı kimlikli kartta bu iki alan isteğe bağlıdır.
  • İl ve ilçe (address.city, address.district) e-Fatura ve e-Arşiv gönderimi için gereklidir. Biri boşsa o karta kesilen fatura gönderimde 400 validation_failed alır (details.field: contact_id).
  • Aynı firmada kayıtlı bir kartla çakışma 409 conflict alır (details.field çakışan alanı gösterir). Denetim cari tipine göre değişir: PERSONEL dışındaki kartlarda tax_number, PERSONEL kartlarında national_id tekil olmalıdır; code her tipte tekildir.
  • Bu uç Idempotency-Key okumaz: isteği yeniden göndermek ikinci bir kart açar.

Yanıt 201 ve kartın kendisidir. Faturada kullanacağınız değer data.id’dir:

JSON, 201
{
  "data": {
    "id": "0192e8a1-7c3f-7d2e-b5a4-3f6c9d8e1a20",
    "code": "C-000123",
    "title": "Örnek Ticaret Ltd. Şti.",
    "type": "MUSTERI",
    "person_type": "TUZEL",
    "tax_number": "1234567890",
    "tax_office": "Kadıköy",
    "status": "active",
    "address": {
      "line": "Örnek Mah. Deneme Sok. No: 1",
      "district": "Kadıköy",
      "city": "İstanbul"
    },
    "created_at": "2026-10-04T09:12:41.482913Z",
    "updated_at": "2026-10-04T09:12:41.482913Z"
  }
}

Mevcut bir cari kartı bulmak

Dış API cari kartları listelemez, tek tek okumaz ve VKN, TCKN ya da unvanla arama sunmaz. Bu yüzden kartı açarken dönen id’yi kendi müşteri kaydınızla eşleyip saklayın. VKN çakışmasındaki 409 yanıtı çakışan alanı söyler, mevcut kartın id’sini taşımaz. Ayrıntı: Müşteri (cari) bilgilerini okuma.

2. e-Fatura mı, e-Arşiv mi?

Belge türü alıcının durumuna bağlıdır: alıcı GİB’de e-Fatura mükellefiyse e-Fatura, değilse e-Arşiv kesilir. Alıcı e-Fatura mükellefiyken e-Arşiv kesmek belgeyi hukuken geçersiz kılar; gönderim bu durumu 422 invalid_state ile reddeder. Sorgu için alıcının VKN ya da TCKN’si yeter:

JSON, GET /v1/e-invoice-inboxes/1234567890
{
  "data": {
    "tax_number": "1234567890",
    "title": "Örnek Ticaret Ltd. Şti.",
    "e_invoice_user": true,
    "e_despatch_user": false,
    "addresses": [
      {
        "address": "urn:mail:defaultpk@ornek.com.tr",
        "document_type": "FATURA",
        "direction": "inbox"
      }
    ]
  }
}
  • e_invoice_user: true ise document_type: E_FATURA kesin. recipient_mailbox olarak addresses içindeki, silinmemiş (deleted_at olmayan) direction: inbox etiketini verin; e-Fatura gönderiminde zorunludur.
  • e_invoice_user: false ise document_type: E_ARSIV kesin.
  • Dizinde bulunmayan VKN 404 döndürmez; e_invoice_user: false taşıyan geçerli bir yanıt verir.

3. Taslağı oluşturun

POST /v1/invoices yalnız taslak yazar; GİB’e hiçbir şey göndermez. Gönderim ayrı ve açık bir adımdır. Satır toplamları, KDV matrahı ve tevkifat sunucuda hesaplanır; gövdede gönderdiğiniz toplamlar yok sayılır.

JSON, POST /v1/invoices
{
  "document_type": "E_ARSIV",
  "invoice_type": "SATIS",
  "scenario": "EARSIV_FATURA",
  "issue_date": "2026-10-04",
  "contact_id": "0192e8a1-7c3f-7d2e-b5a4-3f6c9d8e1a20",
  "currency": "TRY",
  "notes": ["Sipariş no: 1042"],
  "items": [
    {
      "name": "Danışmanlık hizmeti",
      "quantity": 2,
      "unit": "ADET",
      "unit_price": 500,
      "vat_rate": 20
    }
  ]
}

Zorunlu alanlar: document_type, invoice_type, scenario, issue_date, contact_id ve her kalem için name, quantity, unit, unit_price, vat_rate. Örnek e-Arşiv içindir; e-Fatura için şunlar değişir:

quantity en çok 6 ondalık, unit_price en çok 4 ondalık alır; fazlası yuvarlanmadan kesilir ("quantity": 1.1234567 kaydedilince 1.123456 olur). Satır tutarı, matrah, vergi ve toplamlar sunucuda 2 haneye normal yuvarlamayla hesaplanır.

  • document_type E_FATURA, scenario TEMEL_FATURA (ya da TICARI_FATURA).
  • recipient_mailbox: alıcının GİB posta kutusu etiketi (urn:mail:…), önceki adımdan.
  • e-Arşiv belgesinde (E_ARSIV) recipient_email: faturanın PDF’inin gönderimden sonra iletileceği adres. Boş bırakılırsa carinin e-postası kullanılır.

İade faturasında (IADE, TEVKIFAT_IADE, YTB_IADE, YTB_TEVKIFAT_IADE) iade edilen faturanın numarasını return_invoice_number (boşluksuz 16 karakter, örneğin ABC2026000000001) ve tarihini return_invoice_date alanına yazın. Yatırım Teşvik senaryosunda (YATIRIM_TESVIK) ve e-Arşiv’in YTB tiplerinde teşvik belgesinin numarası incentive_certificate_number (6 haneli sayı), tarihi incentive_certificate_date alanıdır. Taslak bu alanlar olmadan da kaydedilir; gönderimde zorunludur.

Yanıt 201 ve taslaktır. Sonraki bütün isteklerde kullanacağınız kimlik id’dir; saklayın:

JSON, 201
{
  "data": {
    "id": "0192e8b4-5a10-7e6b-8c21-9d4f0a7b3c55",
    "document_type": "E_ARSIV",
    "invoice_type": "SATIS",
    "scenario": "EARSIV_FATURA",
    "contact_title": "Örnek Ticaret Ltd. Şti.",
    "tax_number": "1234567890",
    "issue_date": "2026-10-04",
    "total": "1200.00",
    "currency": "TRY",
    "status": "draft",
    "created_at": "2026-10-04T09:14:02.118204Z",
    "updated_at": "2026-10-04T09:14:02.118204Z"
  }
}

Doğrulama hatalarında details.field gövdedeki alan adıdır (items[0].vat_rate gibi). issue_date bugünden (Europe/Istanbul) ileri olamaz; TRY dışı belgede exchange_rate gerekir; ikisi de 422 invalid_state alır. contact_id bu firmada yoksa 404 döner. Bütün alanlar OpenAPI referansındadır.

Fatura id’si, fatura numarası ve ETTN farklıdır

Faturada üç ayrı kimlik vardır ve karıştırılmaları en sık yapılan hatadır:

AlanNedirNe zaman gelir
idSistemin ürettiği iç UUID. Fatura uçlarının yolunda kullanılır: /v1/invoices/{id}, /v1/invoices/{id}/send.Taslak oluşturulunca, POST /v1/invoices yanıtında.
invoice_noFatura numarası (seri ve sayaç). Müşteriye gösterilen numaradır.Taslakta gelmez; numara gönderimde atanır: ön ek (varsayılan FAT) + belge yılı + 9 haneli sıra. Seri e-belge servisine bağlıysa alan, e-belge servisi numarayı bildirdiğinde dolar.
uuidETTN: belgenin GİB’deki tekil kimliği.Belge e-belge servisine gönderilene kadar gelmez.
envelope_idZarf kimliği: e-Faturanın alıcıya gönderildiği zarfın ETTN’si. Değer e-belge servisinin bildirdiğidir.Yalnız e-Fatura’da, belge alıcıya zarflanınca gelir; e-Arşiv’de ve taslakta yoktur.

Seri ve numarayı API vermez, seri açmak da gerekmez

Taslak gövdesinde invoice_no ya da seri alanı yoktur: API’den seri seçilmez, numara verilmez. Numara gönderimde atanır.

Numaratör (seri) tanımlamak önkoşul değildir. Firmanın varsayılan numaratörü yoksa fatura yedek FAT serisiyle numara alır: numara ön ek + belge yılı (fatura tarihinin yılı) + 9 haneli sıradır, örneğin FAT2026000000001. FAT ilk kullanımda firmaya numaratör olarak kaydedilir.

Kendi ön ekini isteyen firma (örneğin ABC2026000000001) numaratörü kendi panelinde Firma Bilgileri → Belge Ayarları ekranındaki belge tipi sekmesinden Yeni Numaratör Ekle ile açar; bayi (iş ortağı) panelinin Belge Ayarları ekranından ya da YouSoft ekibi de açabilir. Müşteri panelinde bu işlem için firma bilgileri yetkisi gerekir. Ön ek tam 3 haneli olmalı ve yalnız A-Z ile 0-9 içermelidir. API ile seri yönetilmez.

Seri e-belge servisine bağlıysa numarayı gönderim sırasında e-belge servisi verir. Bu yüzden invoice_no taslakta ve e-belge servisi numarayı bildirene kadar gönderilmiş belgede de görünmez. Numarayı gönderimden sonra GET /v1/invoices/{id} ile okuyun; alanın o ana kadar yokluğu hata değildir.

4. Gönderim önkoşulları

send çağrıldığında önce taslağın gönderilebilir olduğu doğrulanır. Bir önkoşul eksikse yanıt hemen döner, message nedeni söyler ve taslak yerinde kalır: eksiği giderip aynı uca yeniden istek gönderebilirsiniz. Çoğu önkoşul 422 invalid_state verir; istisnalar tablolarda yazılıdır.

Firma ve hesap tarafı

Bunların çoğu firma tarafında bir kerelik panel işidir ve API ile yapılamaz; firma yetkilisinin panelden tamamlaması gerekir. Numaratör bunlardan biri değildir: tanımlı değilse FAT serisi kullanılır (Seri ve numara).

ÖnkoşulEksikse
Firmanın e-Belge Tanımları’nda ilgili belge türü (e-Fatura ya da e-Arşiv) açık olmalı.422 invalid_state
Firmanın varsayılan GİB gönderici etiketi tanımlı olmalı.422 invalid_state
Firma bilgilerinde vergi dairesi, il ve ilçe dolu olmalı. details.field boş gelir; mesaj Firma Bilgileri’nin tamamlanmasını söyler.422 invalid_state
Ödeme gecikmemiş (vade tarihinden 4 gün sonra kısıt başlar), kontör eşiği ve aşım tavanı dolmamış olmalı.422 invalid_state
Hesap belge kesmeye açık olmalı: firma pasif olmamalı, deneme süresi dolmamış olmalı.403 forbidden

Belge tarafı

ÖnkoşulEksikse
Fatura tarihi bugünden ileri olmamalı.422 invalid_state
Fatura tarihi bugünden 7 günden fazla geride ise gövdede backdate_confirmed: true olmalı (VUK 231/5).422 invalid_state
TRY dışındaki belgede exchange_rate olmalı.422 invalid_state
e-Arşiv alıcısı GİB e-Fatura kayıtlı kullanıcısı olmamalı. Alıcının kaydı doğrulanamazsa da aynı kod döner: sonra yeniden deneyin.422 invalid_state
e-Fatura için recipient_mailbox verilmiş olmalı.400 validation_failed (details.field: recipient_mailbox)
e-Arşiv için alıcı e-postası olmalı: recipient_email ya da boşsa carinin e-postası.400 validation_failed (details.field: recipient_email)
Cari kartta il ve ilçe dolu olmalı.400 validation_failed (details.field: contact_id)
GİB’in belge kuralları sağlanmalı. Örnek: KDV oranı 0 olan satır exemption_code ister (satışta 351).400 validation_failed (details.field gövdedeki alan adı)
İade faturasında iade edilen faturanın numarası ve tarihi, Yatırım Teşvik senaryosunda ve e-Arşiv’in YTB tiplerinde teşvik belgesinin numarası ve tarihi dolu olmalı.400 validation_failed (details.field: return_invoice_number ya da incentive_certificate_number)
Belge türü API’den gönderilebilir olmalı. Bugün tevkifat tipleri (iadeleri dahil), e-Arşiv’in YTB tipleri ve Yatırım Teşvik senaryosu API’den gönderilemez: kalem tevkifat kodu ve kalemin teşvik harcama tipi API gövdesinde yok, bu taslaklar panelden tamamlanır.400 validation_failed (details.field boş, mesaj panelden tamamlanmasını söyler)

5. Faturayı gönderin

POST /v1/invoices/{id}/send taslağı gönderim kuyruğuna alır. Gövde isteğe bağlıdır; yalnız fatura tarihi 7 günden fazla geride ise onay gerekir:

JSON, POST /v1/invoices/{id}/send
{ "backdate_confirmed": true }

Başarılı yanıt 202 ve yalnız kabul edilen belgenin kimliğidir:

JSON, 202
{
  "data": { "invoice_id": "0192e8b4-5a10-7e6b-8c21-9d4f0a7b3c55" }
}

202, belgenin GİB’e ulaştığı anlamına gelmez. İmzalama ve iletim arka planda olur; sonucu bir sonraki adımdaki gibi siz sorarsınız. Her gönderim niyeti için Idempotency-Key başlığı gönderin: aynı anahtarla gelen ikinci istek saklanan 202 yanıtını döndürür ve GİB’e ikinci bir gönderim olmaz. Anahtar en çok 255 karakter olabilir ve 24 saat saklanır; ayrıntı Sorgu sözleşmesinde.

6. Sonucu izleyin

Gönderim eşzamansız çalışır ve sonuç için bildirim çağrısı (webhook) yoktur: sonucu GET /v1/invoices/{id} ile status alanından sorarsınız (poll). Bu uç taslağı da gönderilmiş faturayı da okur. Başarılı gönderimde invoice_no ve uuid da dolar:

JSON, 200
{
  "data": {
    "id": "0192e8b4-5a10-7e6b-8c21-9d4f0a7b3c55",
    "document_type": "E_ARSIV",
    "invoice_type": "SATIS",
    "scenario": "EARSIV_FATURA",
    "invoice_no": "FAT2026000000001",
    "uuid": "5f0c2d7e-3a1b-4c8d-9e6f-1a2b3c4d5e6f",
    "contact_title": "Örnek Ticaret Ltd. Şti.",
    "tax_number": "1234567890",
    "issue_date": "2026-10-04",
    "total": "1200.00",
    "currency": "TRY",
    "status": "sent",
    "status_detail": "GIBE_GONDERILDI",
    "payment_status": "not_due",
    "created_at": "2026-10-04T09:14:02.118204Z",
    "updated_at": "2026-10-04T09:15:11.640371Z"
  }
}

status yedi değerden biridir; status_detail aynı durumun daha ayrıntılı halini taşır (taslakta gelmez). Kodunuz status ile dallansın, status_detail izleme ve destek içindir.

statusAnlamıstatus_detail değerleri
draftTaslak, henüz gönderilmedi.yok
sendingKuyrukta ya da GİB’e iletiliyor. Beklemeye devam edin.GONDERIM_IZNI_BEKLIYOR, ARSIV_FATURA_KAYIT_KUYRUGUNDA, RAPOR_OLUSTURULACAK, GIBE_GONDERILECEK, TEKRAR_GONDERIM_KUYRUGUNDA, GONDERIM_BELIRSIZ
sentGİB’e iletildi. Alıcının yanıtı bekleniyorsa durum burada kalır; yanıt gelince accepted ya da rejected olur.GIBE_GONDERILDI, ALICIYA_ULASTI, YANIT_BEKLENIYOR
acceptedKabul edildi. Alıcı yanıt süresinde yanıt vermezse belge zımnen kabul edilir ve o da accepted olur.ONAYLANDI, KABUL, OTOMATIK_KABUL
rejectedAlıcı reddetti.RED
failedGönderim başarısız oldu. Yanıt hatanın nedenini taşımaz; ne yapacağınız aşağıda.HATA
cancelledİptal edildi ya da yeniden düzenlendi.IPTAL_EDILECEK, IPTAL_EDILDI, YENIDEN_DUZENLENDI

Ne sıklıkla sorulur

Sık sormak sonucu hızlandırmaz, yalnız oran sınırınızı tüketir: anahtar başına dakikada 120 istek, firmanın bütün anahtarları için toplam dakikada 300 istek ve bütün uçlar aynı genel kotayı paylaşır (Oran sınırı). İlk sorguyu birkaç saniye sonra atın, sonra 30 saniye gibi aralıklarla sorun. Çok sayıda bekleyen fatura varsa her birini ayrı ayrı sormak yerine listeyi durumla süzün (filter[status][eq]=sending) ya da kayan pencereyle okuyun.

Gönderim başarısız olursa

failed gördüğünüzde önce önkoşulları ve e-belge entegrasyonunu kontrol edin, sonra yeniden gönderin. Yeniden deneme yeni bir gönderim niyetidir: aynı Idempotency-Key yalnız ilk yanıtı yineler, yeni deneme başlatmaz; bu yüzden yeni bir anahtar kullanın ya da anahtarsız gönderin. Sonuç belgenin o anki durumuna bağlıdır:

  • failed, belge e-belge servisine hiç ulaşmamışsa: yeniden kuyruğa alınır, 202. ETTN değişmez; numara çakışması nedeniyle düşmüşse fatura numarası yenilenir.
  • failed, belge e-belge servisine ulaşmışsa: 409 conflict, yeniden gönderim yoktur.
  • sent, accepted, rejected, cancelled: 409 conflict.
  • sending: 5 dakikadan uzun süredir takılı kalmış belge (GIBE_GONDERILECEK) yeniden kuyruğa alınır, 202. Sonucu belirsiz belgede (GONDERIM_BELIRSIZ) belge yeniden yüklenmez; 202 döner ve sonuç e-belge servisinden sorgulanarak netleşir. Diğer sending durumları 409 alır. Tam liste sendInvoice açıklamasındadır.

Zaman aşımı ya da 5xx aldıysanız istek işlenmiş olabilir: yeniden göndermeden önce status alanını okuyun. Ağ hatasında yeniden denerken aynı Idempotency-Key’i kullanın; 24 saatten eski bir anahtar yeni istek sayılır.

Gönderimden sonra

Faturayı kestikten sonra ihtiyaç duyulan uçlar ve gereken kapsamları:

İşUç ve gereken kapsam
Giden faturaları listeleyin ve bulunGET /v1/invoices
EFatura.GidenKutusuIzleyebilir
Giden faturanın XML’ini indirinGET /v1/invoices/{id}/xml
EFatura.GidenKutusuIzleyebilir
Giden faturanın PDF’ini indirinGET /v1/invoices/{id}/pdf
EFatura.GidenKutusuIzleyebilir
Gönderilmiş faturayı iptal edinPOST /v1/invoices/{id}/cancel
EFatura.IptalEdebilir
Gelen faturaları listeleyinGET /v1/inbox-invoices
EFatura.GelenKutusuIzleyebilir
Gelen faturayı okuyunGET /v1/inbox-invoices/{id}
EFatura.GelenKutusuIzleyebilir
Gelen faturanın XML’ini indirinGET /v1/inbox-invoices/{id}/xml
EFatura.GelenKutusuIzleyebilir
Gelen faturanın PDF’ini indirinGET /v1/inbox-invoices/{id}/pdf
EFatura.GelenKutusuIzleyebilir

Faturaları listeleme ve bulma

GET /v1/invoices taslakları ve gönderilmiş faturaları tek listede döndürür; taslak status: draft taşır. Liste e-Fatura, e-Arşiv, ihracat, ilaç ve tıbbi cihaz, kamu, SGK, proforma ve iade belgelerini kapsar (document_type: E_FATURA, E_ARSIV, E_IHRACAT, E_ILAC_TIBBI, E_KAMU, E_SGK, PROFORMA, IADE); makbuz, irsaliye ve e-Döviz belgeleri bu listede yoktur. Arşivlenen belge listeden düşer, ama GET /v1/invoices/{id} onu da okur.

Liste belge tarihine göre sıralanır (varsayılan -issue_date, en yeni önce). Süzgeçler: filter[issue_date][gte] ve [lte] (gün, YYYY-MM-DD), filter[status][eq], filter[document_type][eq], filter[invoice_no][eq], filter[uuid][eq] (ETTN) ve filter[envelope_id][eq] (zarf kimliği). Kurallar Sorgu sözleşmesinde. include=contact her satıra seçilen cari kartı ekler ve cari okuma kapsamını ister.

bash
# Fatura numarasıyla
imzali GET "/v1/invoices?filter[invoice_no][eq]=YSF2026000000012" ''
# ETTN ile
imzali GET "/v1/invoices?filter[uuid][eq]=0191e541-1685-7953-a18b-075029fefd2c" ''
# Zarf kimliğiyle (yalnız e-Fatura)
imzali GET "/v1/invoices?filter[envelope_id][eq]=0191e5c2-7b10-7d4e-9a51-2f6e8c1d3b70" ''

Numara ya da kimlikle arama tam eşleşmedir; bulunamazsa liste boştur (404 değil). Genellikle tek satır döner ama birden çok satır gelebilir: aynı numara farklı belge tiplerinde bulunabilir, bir zarfta birden çok belge olabilir. Eşlerken document_type alanına da bakın. Zarf kimliği yalnız e-Fatura satırlarında doludur ve e-belge servisinin bildirdiği değerdir.

Kendi kaydınızla eşitlemek: kayan pencere

“Son okuduğumdan beri değişenler” süzgeci yoktur: liste belge tarihine göre sıralanır ve durumu değişen belge listede yer değiştirmez. Bir faturanın durumu belge tarihinden sonra da değişir: ticari e-Faturada alıcı belge tarihinden sonraki 7 gün içinde yanıt verir, e-Arşiv faturası GİB’e iletildiği günden itibaren 8 gün içinde iptal edilebilir. Önerilen yol, her turda son 30 günün faturalarını baştan sona okumaktır.

Pencere bir üst sınır garantisi değildir: geriye tarihli bir belge iletildikten sonra iptal edilebilir, e-Faturanın dış kanalda yapılmış iptali de herhangi bir gün kaydedilebilir. Bunları kaçırmamak için dönemi kapatmadan önce o dönemin tamamını bir kez daha okuyun (filter[issue_date][gte] ve [lte] ile); tek bir belgeyi doğrulamak için GET /v1/invoices/{id} yeterlidir.

bash
# Her turda son 30 günün faturalarını baştan sona okuyun ve kendi kaydınızla eşleyin
BASLANGIC=$(date -v-30d +%Y-%m-%d)   # GNU date: date -d '30 days ago' +%Y-%m-%d
imzali GET "/v1/invoices?filter[issue_date][gte]=$BASLANGIC&page_size=100" ''
# meta.next_cursor null olana kadar aynı süzgeçle cursor ekleyerek devam edin

# Gelen faturalarda pencere 45 gündür
BASLANGIC=$(date -v-45d +%Y-%m-%d)   # GNU date: date -d '45 days ago' +%Y-%m-%d
imzali GET "/v1/inbox-invoices?filter[issue_date][gte]=$BASLANGIC&page_size=100" ''

XML ve PDF indirme

Gönderilmiş bir faturanın UBL XML’i GET /v1/invoices/{id}/xml, PDF’i GET /v1/invoices/{id}/pdf ile indirilir; gelen faturalar için aynı uçlar /v1/inbox-invoices/{id} altındadır. Biçim yalnız XML ve PDF’tir.

bash
imzali GET "/v1/invoices/$FATURA_ID/xml" '' -o fatura.xml
imzali GET "/v1/invoices/$FATURA_ID/pdf" '' -o fatura.pdf
  • Yanıt 200 ve dosyanın kendisidir: Content-Type application/xml; charset=utf-8 ya da application/pdf, Content-Disposition: attachment ve fatura numarası (yoksa ETTN) adlı dosya.
  • XML bayt bayt e-belge servisindeki hâliyle gelir ve imzalıdır. Saklarken yeniden biçimlendirmeyin, girintilemeyin ya da kodlamasını değiştirmeyin: imza bozulur. Simülasyon ortamında kesilen belgenin XML’i imzasızdır ve yerelde üretilir.
  • Taslak indirilemez: 422 invalid_state, önce gönderin. Henüz e-belge servisine ulaşmamış belge, elle kaydedilmiş gelen belge ve e-belge entegrasyonu tamamlanmamış firma da 422 alır.
  • Belge bu firmada yoksa ya da bu uçların kapsamında değilse (makbuz, irsaliye) 404 döner.
  • e-belge servisi hata verirse yanıt 500 internal_error olur; indirme salt okumadır, yeniden denenebilir. Destek kaydında details.request_id değerini paylaşın.
  • İndirme uçlarının ayrı ve daha dar bir kotası ve firma başına aynı anda 4 indirme sınırı vardır (Oran sınırı). Toplu indirmede 4’ten fazla paralel istek açmayın; fazlası 429 alır.

İptal

POST /v1/invoices/{id}/cancel gönderilmiş bir faturayı iptal eder ve geri alınamaz. Taslak bu uçtan iptal edilmez. Gereken kapsam EFatura.IptalEdebilir varsayılan kümededir; anahtar üretilirken panelde Fatura iptaline izin ver kutusu kaldırıldıysa anahtar bu kapsamı taşımaz ve istek 403 alır (Kapsamlar).

JSON, POST /v1/invoices/{id}/cancel
{
  "objection_type": "GIB",
  "reason": "Hatalı tutar"
}
  • e-Arşiv: GİB’e ulaşmış e-Arşiv faturası e-belge servisinde iptal edilir ve iptal GİB’e iptal raporuyla bildirilir; kayıt yalnız bu işlem başarılıysa iptal olur. Yalnız objection_type: GIB kabul edilir. İptal tarihi işlem günüdür: cancel_date verilmezse bugündür, başka bir gün verilirse reddedilir. İptal, belgenin GİB’e iletildiği günden itibaren 8 gün içinde (son gün dahil) yapılabilir; sonrası 422 invalid_state. Geriye tarihli belgede süre belge tarihinden değil iletim gününden işler.
  • e-Fatura: bu uç GİB’e talep göndermez. e-Faturanın iptali alıcıyla dış kanalda (GİB, KEP, noter ya da taahhütlü mektup) yapılır; bu istek o itirazın ya da iptalin kaydıdır ve kanal objection_type ile yazılır.
  • Zaten iptal edilmiş, yeniden düzenlenmiş ya da gönderimi süren belge 409 conflict alır.
  • e-belge servisi hata verirse yanıt 500 internal_error olur ve fatura değişmemiştir; istek tekrarlanabilir.

Gelen faturalar

GET /v1/inbox-invoices karşı tarafın firmaya gönderdiği faturaları listeler, GET /v1/inbox-invoices/{id} tek birini okur. Taslak aşaması yoktur: status hiçbir zaman draft ya da sending olmaz. Sıralama ve süzgeç adları giden listeyle aynıdır, değer kümeleri farklıdır: status yalnız sent, accepted, rejected ve cancelled; document_type yalnız E_FATURA (iade, kamu, ihracat gibi ayrımlar invoice_type ve scenario alanlarındadır). envelope_id süzgeci ve alanı gelen faturada yoktur. e-İrsaliye bu listede değildir.

  • Fatura numarası gelen faturada benzersiz değildir: iki farklı tedarikçi aynı numarayla fatura gönderebilir. filter[invoice_no][eq] birden çok satır döndürebilir; gönderenleri sender_tax_number ile ayırın.
  • Gelen belge bize belge tarihinden günler sonra ulaşabilir (received_at) ve listede issue_date’ine göre eski bir yere düşer. Bu yüzden gelende kayan pencereyi daha geniş tutun (son 45 gün) ve dönemi kapatmadan önce o dönemi bir kez tam okuyun.
  • Bize ulaşırken işlenemeyen belge (alımında hata oluşmuş belge) listede görünmez; tekil okuması ve indirmesi 404 döner. Hata giderilince belge gerçek durumuyla listeye girer. Bu yüzden gelen listede failed süzgeci yoktur. Düzeltilen belgenin tarihi kayan pencerenizin dışında kalmışsa onu yalnız daha geniş bir tarih aralığıyla görürsünüz.
  • Panelden elle kaydedilmiş (GİB üzerinden gelmemiş) belgede uuid, received_at ve answer_due_date null döner; bu belgenin XML’i ve PDF’i yoktur (422).
  • answer_due_date ticari faturada kabul ya da red için son gündür: belge tarihinden sonraki 7. gün (belge günü sayılmaz). Yanıt dış API’den verilmez, panelden verilir.

Tam akış örneği

Önce her isteği imzalayan küçük bir işlev tanımlayın. İmzanın ne yaptığı İmzalama sayfasında anlatılır; Postman kullanıyorsanız Postman sayfası aynı işi koleksiyon betiğiyle yapar.

bash
# İmzalı istek: imzali METOT YOL GÖVDE [ek curl bağımsız değişkenleri]
# API_KEY ve API_SECRET tanımlı olmalı (Hızlı başlangıç); yanıtları ayrıştırmak için jq gerekir.
TABAN='https://api.yousoft.com.tr'

imzali() {
  local METOT=$1 YOL=$2 GOVDE=$3
  shift 3
  local TS OZET IMZA
  TS=$(date +%s)
  OZET=$(printf '%s' "$GOVDE" | openssl dgst -sha256 -hex | awk '{print $NF}')
  IMZA=$(printf '%s\n%s\n%s\n%s' "$TS" "$METOT" "$YOL" "$OZET" \
    | openssl dgst -sha256 -hmac "$API_SECRET" -hex | awk '{print $NF}')
  if [ -n "$GOVDE" ]; then set -- --data-binary "$GOVDE" "$@"; fi
  curl -sS -g -X "$METOT" "$TABAN$YOL" \
    -H "X-Api-Key: $API_KEY" \
    -H "X-Api-Timestamp: $TS" \
    -H "X-Api-Signature: $IMZA" \
    -H 'Content-Type: application/json' "$@"
}

Ardından beş adım, sırayla:

bash
# 1. Cari kartı oluşturun ve id'sini alın
CARI=$(imzali POST /v1/contacts '{
  "title": "Örnek Ticaret Ltd. Şti.",
  "type": "MUSTERI",
  "person_type": "TUZEL",
  "tax_number": "1234567890",
  "tax_office": "Kadıköy",
  "address": { "district": "Kadıköy", "city": "İstanbul" }
}')
CARI_ID=$(printf '%s' "$CARI" | jq -r '.data.id')

# 2. Alıcı e-Fatura mükellefi mi? false ise e-Arşiv, true ise e-Fatura keseceksiniz
imzali GET /v1/e-invoice-inboxes/1234567890 '' | jq '.data.e_invoice_user'

# 3. Taslağı oluşturun (e-Arşiv örneği) ve id'sini alın
GOVDE=$(cat <<TASLAK
{
  "document_type": "E_ARSIV",
  "invoice_type": "SATIS",
  "scenario": "EARSIV_FATURA",
  "issue_date": "$(TZ=Europe/Istanbul date +%F)",
  "contact_id": "$CARI_ID",
  "items": [
    { "name": "Danışmanlık hizmeti", "quantity": 2, "unit": "ADET", "unit_price": 500, "vat_rate": 20 }
  ]
}
TASLAK
)
FATURA=$(imzali POST /v1/invoices "$GOVDE")
FATURA_ID=$(printf '%s' "$FATURA" | jq -r '.data.id')

# 4. Gönderime alın. Anahtarı saklayın: aynı gönderimi yeniden denerken aynısını verin
ANAHTAR=$(uuidgen)
imzali POST "/v1/invoices/$FATURA_ID/send" '{}' -H "Idempotency-Key: $ANAHTAR"

# 5. Sonucu izleyin: sending sürüyor demektir, gerisi sonuçtur
while :; do
  DURUM=$(imzali GET "/v1/invoices/$FATURA_ID" '' | jq -r '.data.status')
  echo "durum: $DURUM"
  case "$DURUM" in draft|sending) sleep 30 ;; *) break ;; esac
done

Müşteri (cari) bilgilerini okuma

Dış API cari kartları listelemez ve tek bir kartı da okumaz; carinin ekstresi, bakiyesi ve iletişim kişileri de dış API’de yoktur, panelden bakılır. Cari kart uçları yazma içindir: POST /v1/contacts kart açar, PATCH /v1/contacts/{id} günceller, POST /v1/contacts/{id}/people iletişim kişisi ekler. Kartı açarken dönen id’yi saklayın (Mevcut bir cari kartı bulmak).

Faturayı cari bilgisiyle birlikte okuma

Bir faturanın alıcı kartını faturayla birlikte okuyabilirsiniz: GET /v1/invoices/{id} isteğine include=contact verin.

bash
imzali GET "/v1/invoices/$FATURA_ID?include=contact" ''
  • Kart, faturanın contact alanında gelir ve belge düzenlenirken seçilen karttır.
  • include=contact ayrıca Kart.MusteriTedarikciIzleyebilir kapsamını ister; anahtar bunu taşımıyorsa istek 403 forbidden alır, include vermeyen istek etkilenmez.
  • Kart belirlenemeyen belgede contact alanı hiç gelmez; bu hata değildir. Belgenin kendi contact_title ve tax_number alanları her zaman bulunur (Genişletme).