> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flextell.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Rehber: satış, tahsilat ve fatura

> Satış oluşturmayı, ödeme kaydetmeyi ve satıştan fatura kesmeyi uçtan uca örnekle anlatır.

Bu rehber, bir Hastaya satış kaydetmekten o satışın faturasını kesmeye kadar olan akışı tek bir örnek üzerinden gösterir: satışı oluşturur, iki parça tahsilat kaydeder, e-SMM keser ve faturanın durumunu izlersiniz. Rehber entegratörler içindir; alan alan ayrıntı için [Satışlar](/api/kaynaklar/satislar), [Hesaplar ve işlemler](/api/kaynaklar/hesaplar-ve-islemler) ve [Faturalar](/api/kaynaklar/faturalar) sayfalarına bakın.

## Senaryo

Ayşe Yılmaz (Hasta `123`) bir Tedavi (`67`) için gelir. Tedavi KDV hariç 2.500 TL'dir, %20 KDV uygulanır ve Hastaya %10 indirim yapılır. Hasta 1.000 TL'yi nakit, kalanı kredi kartıyla öder. Ardından klinik satış için e-SMM keser.

```mermaid theme={null}
flowchart LR
  A[Satış oluştur] --> B[Tahsilat 1: nakit]
  B --> C[Tahsilat 2: kredi kartı]
  C --> D[Fatura önizle]
  D --> E[Fatura kes]
  E --> F[Durumu izle]
```

Örnekteki tutarlar şöyle hesaplanır:

| Değer | Hesap | Sonuç |
| - | - | - |
| Ara toplam (`sub_total`) | 1 × 2.500 | 2.500 TL |
| İndirim (`total_discount`) | 2.500 × %10 | 250 TL |
| KDV (`total_tax`) | (2.500 − 250) × %20 | 450 TL |
| Satış toplamı (`total_price`) | 2.250 + 450 | 2.700 TL |

### Ön koşullar

* `Authorization: Bearer <access_token>` ve `X-Tenant: <tenant_id>` başlıkları. Bkz. [Hızlı başlangıç](/api/hizli-baslangic) ve [Klinikler ve X-Tenant](/api/klinikler-ve-x-tenant).
* Aşağıdaki tabloda yazan scope'lar ve kullanıcı izinleri. Scope'lar için [Scope'lar](/api/kimlik-dogrulama/scopelar), izinler için [İzinler ve görünürlük](/api/izinler-ve-gorunurluk) sayfasına bakın.
* Kliniğinizde e-SMM kesebilen bir fatura hesabı. Hesap kurulumu için [e-Fatura entegrasyonu](/api/entegrasyonlar/e-fatura) sayfasına bakın.
* Satıştaki Hasta, kalem personeli (`staff_id`) ve Tedavi için kimlikler. Bkz. [Hastalar](/api/kaynaklar/hastalar) ve [Tedaviler](/api/kaynaklar/tedaviler).

| Adım | İstek | Scope | İzin |
| - | - | - | - |
| Satış oluşturma | `POST /sales` | `sales:write` | `Create:Sale` |
| Tahsilat | `POST /sales/{id}/payments` | `sales:write` | `Pay:Sale` |
| Satışı okuma | `GET /sales/{id}` | `sales:read` | `View:Sale` |
| Hesap ve seri | `GET /invoices/accounts`, `GET /invoices/series` | `invoices:read` | `View:Invoice` veya `Create:Invoice` |
| Önizleme ve fatura | `POST /invoices/preview`, `POST /invoices` | `invoices:write` | `Create:Invoice` ve `CreateDocument:Sale` |
| Durum sorgusu | `POST /invoices/{id}/query-status` | `invoices:write` | `QueryStatus:Invoice` |

<Info>
  `ViewAllSales:Sale` izniniz yoksa yalnızca kendi satışlarınızı ya da Hastanın lead'i size atanmış satışları görürsünüz. Kapsam dışındaki satış `403` değil `404` döner.
</Info>

## Satış oluşturma

`POST /api/v1/sales` satışı ve kalemlerini tek işlemde oluşturur. Sunucu kalem toplamlarını her zaman kendisi hesaplar; gönderdiğiniz `sub_total`, `total_discount` ve `total_tax` değerleri yok sayılır.

Para birimi için `currency_id` gerekir. Kimliği `GET /api/v1/sales/form-metadata` yanıtındaki `base_currency` alanından alabilirsiniz. Baz para biriminde `exchange_rate` değerini `1` gönderin.

```bash title="Satış oluşturma" theme={null}
curl -X POST "https://app.flextell.ai/api/v1/sales" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": 123,
    "currency_id": 1,
    "exchange_rate": 1,
    "status": "completed",
    "sale_date": "2026-10-12T14:30:00+03:00",
    "items": [
      {
        "staff_id": 45,
        "itemable_type": "Treatment",
        "itemable_id": 67,
        "quantity": 1,
        "unit_price": 2500,
        "tax_rate": 20,
        "discount_amount": 0,
        "discount_percentage": 10
      }
    ]
  }'
```

Başarılı yanıt `201` ve satış detayıdır. Yanıttaki `id` değerini sonraki adımlarda kullanın. Bu rehberde satış kimliği `123`, sonradan oluşacak fatura kimliği `456` olarak kabul edilir; tüm kimlikler örnektir.

<Warning>
  `unit_price` KDV hariçtir. `staff_id`, `discount_amount` ve `discount_percentage` her kalemde zorunludur. `tax_rate` yalnızca `0`, `1`, `10` veya `20` olabilir.
</Warning>

Satış bu noktada Hastanın alacağı olarak kaydedilir; tahsilat henüz yoktur. Bu endpoint ödeme almaz. Taksitli satış için `is_installment_sale` ve `installments[]` alanlarını kullanın; taksit planını sonradan `PUT` ile değiştiremezsiniz.

## Ödeme kaydetme

`POST /api/v1/sales/{id}/payments` satışa tahsilat ekler. `amount` ve `payment_method` zorunludur; `type` göndermezseniz `collection` (Tahsilat) olur. Ödeme yöntemi değerlerini `GET /api/v1/payment-methods` ile listeleyebilirsiniz.

<Steps>
  <Step title="İlk tahsilat: 1.000 TL nakit">
    ```bash title="Nakit tahsilat" theme={null}
    curl -X POST "https://app.flextell.ai/api/v1/sales/123/payments" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>" \
      -H "Content-Type: application/json" \
      -d '{"amount": 1000, "payment_method": "cash"}'
    ```

    Yanıtta `remaining_balance` değeri `1700` olur.
  </Step>

  <Step title="İkinci tahsilat: 1.700 TL kredi kartı, hesaba işlenerek">
    `account_id` verirseniz tahsilat kasa/banka hesabına da işlenir. Hesabın para birimi `currency_id` ile farklıysa hesabın para birimi geçerli olur.

    ```bash title="Kredi kartı tahsilatı" theme={null}
    curl -X POST "https://app.flextell.ai/api/v1/sales/123/payments" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>" \
      -H "Content-Type: application/json" \
      -d '{"amount": 1700, "payment_method": "credit_card", "account_id": 5}'
    ```

    Yanıtta `remaining_balance` değeri `0` olur.
  </Step>

  <Step title="Hareketleri kontrol edin">
    `GET /api/v1/sales/123/transactions` satışın tüm hareketlerini döner. `meta.collections_by_account` alanı tahsilatları hesaba göre gruplar.
  </Step>
</Steps>

Her yanıt `sale_id`, `remaining_balance` ve oluşan `transaction` nesnesini içerir. Tahsilat ve Hastaya ödeme aynı endpoint'ten geçer: `type` değerini `payment` yaparsanız para Hastaya geri ödenir.

| Kural | Davranış |
| - | - |
| Tutar sınırı | Yok. Toplam tahsilat satış toplamını aşabilir, kalan bakiye 0'ın altına inmez. |
| Satış durumu | Tahsilat `status` alanını değiştirmez. Durumu siz atarsınız. |
| Yanlış hesap veya yöntem | `PUT /sales/{id}/transactions/{transactionId}` ile yalnızca `collection` türündeki hareketin `account_id` veya `payment_method` değerini düzeltin. |
| Hareket silme | `DELETE /sales/{id}/transactions/{transactionId}`; `Pay:Sale` değil `Delete:Sale` ister. |

<Note>
  Satışa tahsilat girdikten sonra kalemleri `PUT` ile değiştirirseniz alacak hareketi güncellenmez ve kalan bakiye eski toplama göre görünür. Tutar değişecekse kalemleri tahsilattan önce güncelleyin.
</Note>

## Fatura oluşturma

Fatura her zaman bir satıştan doğar. Flextell önce e-belge entegratörünü çağırır, sonra yerel kaydı yazar.

<Warning>
  Şu an yalnızca **e-SMM** kesilir. `einvoice` (E-Fatura) türündeki bir hesapla seri, kontör ve fatura çağrıları `*_FAILED` koduyla sonuçlanır. API ile oluşturduğunuz her faturanın `document_class` değeri `SMM`'dir.
</Warning>

<Steps>
  <Step title="Fatura hesabını belirleyin">
    `GET /api/v1/sales/123` yanıtındaki `default_invoice_account_id` önerilen hesabı verir; değer `null` olabilir. `null` ise hesapları listeleyin:

    ```bash title="Hesapları listeleme" theme={null}
    curl "https://app.flextell.ai/api/v1/invoices/accounts?document_type=evoucher&active_integration=true" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>"
    ```

    Bu rehberde seçilen hesap `7`'dir.
  </Step>

  <Step title="Seriyi seçin">
    ```bash title="Seri listesi" theme={null}
    curl "https://app.flextell.ai/api/v1/invoices/series?invoice_account_id=7" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>"
    ```

    Yanıt, seri adlarının haritasıdır (`{"invoice_account_id": 7, "series": {"SMM": "SMM"}}`). Seçtiğiniz adı `series_name` olarak gönderin. Seriler 5 dakika önbellekte tutulabilir.
  </Step>

  <Step title="Önizleyin">
    `POST /api/v1/invoices/preview`, oluşturma ile aynı gövdeyi alır (`mode` hariç) ve hiçbir şey kaydetmeden `html` döner.

    ```bash title="Önizleme" theme={null}
    curl -X POST "https://app.flextell.ai/api/v1/invoices/preview" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>" \
      -H "Content-Type: application/json" \
      -d '{
        "sale_id": 123,
        "invoice_account_id": 7,
        "series_name": "SMM",
        "issue_date": "2026-10-12T14:30:00"
      }'
    ```
  </Step>

  <Step title="Faturayı kesin">
    `mode` değerini `send` yapın. `draft` taslak üretir ve satışın durumunu değiştirmez. Nilvera hesaplarında taslak için ayrı bir uç nokta yoktur; `draft` istekleri de entegratörün gönderim uç noktasına gider. Bu yüzden Nilvera ile çalışıyorsanız `draft` yerine önce önizleme kullanın.

    ```bash title="Fatura kesme" theme={null}
    curl -X POST "https://app.flextell.ai/api/v1/invoices" \
      -H "Authorization: Bearer <access_token>" \
      -H "X-Tenant: <tenant_id>" \
      -H "Content-Type: application/json" \
      -d '{
        "sale_id": 123,
        "invoice_account_id": 7,
        "mode": "send",
        "series_name": "SMM",
        "issue_date": "2026-10-12T14:30:00"
      }'
    ```

    Başarılı yanıt `201` ve fatura nesnesidir; `status` değeri `sent` olur.
  </Step>
</Steps>

`custom_line_items` göndermezseniz her satış kalemi bir fatura satırı olur. Satır tutarı, Hastadan **KDV dahil** tahsil edilen tutar sayılır. Örnekte 2.700 TL için brüt ücret 2.250 TL, KDV 450 TL, ödenecek toplam 2.700 TL'dir. `global_withholding_rate` (0 ile 1 arası kesir) ve diğer alanlar için [Faturalar](/api/kaynaklar/faturalar) sayfasına bakın.

<Tip>
  Kimlik numarası olmayan Hastada entegratör belgeyi reddedebilir. Faturalamadan önce Hastanın adını, kimlik numarasını ve adresini [Hastalar](/api/kaynaklar/hastalar) kaynağından tamamlayın. Aynı satışa daha önce fatura kesilip kesilmediğini `GET /api/v1/invoices?sale_id=123` ile kontrol edin.
</Tip>

Aynı akışı panelden yürütmek için [Tahsilat](/panel/finans/tahsilat) ve [Faturalaştırma](/panel/finans/faturalastirma) sayfalarına bakın.

## Fatura durumunu izleme

Fatura `sent` durumunda kesinleşir; entegratörün işlemi tamamlaması sonradan görünür. Güncel durumu entegratörden almak için sorgulayın:

```bash title="Durum sorgusu" theme={null}
curl -X POST "https://app.flextell.ai/api/v1/invoices/456/query-status" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>"
```

| `status` | Anlamı | Ne yapın |
| - | - | - |
| `sent` | Flextell entegratöre gönderdi. | `query-status` ile sonucu sorgulayın. |
| `waiting` | Entegratör durumu bilinmiyor veya bekliyor. | Bir süre sonra tekrar sorgulayın. |
| `success` | Entegratör işlemi tamamladı. | `GET /invoices/{id}/pdf/download` ile PDF alın. |
| `error` | Entegratör hata bildirdi. | Fatura hesabı ayarlarını ve Hasta bilgilerini kontrol edin. |
| `cancelled` | İptal edildi. | Bu durumda `is_cancelled` alanına güvenin. |

Birden çok faturayı `POST /invoices/query-status` ile toplu sorgulayabilirsiniz; `ids` dizisi 1 ile 100 arası kimlik alır ve yanıt her zaman `200` döner. Başarısız kayıtlar `results[].message` alanında bildirilir.

<Warning>
  İptal bilgisi için `status` yerine `is_cancelled` alanına bakın. Durum sorgusu `cancelled` ya da `draft` değerini entegratörün işlem durumuyla ezebilir; iptal edilmiş bir Nilvera e-SMM'si yeniden sorgulandığında `status=success` ve `is_cancelled=true` görürsünüz.
</Warning>

Satışın kendisini de izleyin. Gönderilmiş faturalar satışın tamamını karşılayınca satış otomatik olarak `invoiced` (**Faturalandırıldı**) olur. Bu satış kilitlidir: `PUT` yalnızca `notes` alanını kabul eder, `DELETE` `422 SALE_INVOICED` döner. Taslak faturalar satışı değiştirmez; taslağı `POST /invoices/{id}/send` ile kesinleştirdiğinizde satış durumu güncellenir.

Faturayı iptal ederseniz (`POST /invoices/{id}/cancel`) `invoiced` olan satış `completed` durumuna döner. İptali `POST /invoices/{id}/revert-cancel` ile geri alırsanız ve kalan faturalanabilir tutar sıfırsa satış yeniden `invoiced` olur.

## Hata durumları

Hata gövdesi `success: false`, `error_code` ve `message` alanlarını taşır. Kodunuzu `message` metnine göre değil `error_code` değerine göre dallandırın. Genel liste için [Hata kodları](/api/istekler/hata-kodlari) sayfasına bakın.

| Kod | HTTP | Ne zaman | Ne yapın |
| - | - | - | - |
| `VALIDATION_FAILED` | 422 | Eksik veya geçersiz alan (örneğin kalemde `staff_id` yok, taksit toplamı satış toplamına eşit değil). | `errors` alanındaki alan adlarına göre isteği düzeltin. |
| `RESOURCE_NOT_FOUND` | 404 | Satış ya da fatura hesabı yok veya görünürlük kapsamınızın dışında. | Kimliği ve `X-Tenant` başlığını kontrol edin. |
| `FORBIDDEN` | 403 | Scope ya da izin eksik (`Pay:Sale`, `CreateDocument:Sale` gibi). | Tablodaki scope ve izinleri kontrol edin. |
| `LEAD_FINANCIAL_BLOCKED` | 422 | Lead aşamasındaki Hasta için satış oluşturuluyor. | Lead'i önce Hastaya dönüştürün. Kliniğin otomatik dönüşüm modu **Satış oluşturulduğunda** ise dönüşüm otomatik olur. |
| `LEAD_NOT_ASSIGNED` | 403 | Başka temsilciye atanmış lead'in satışında yazma. | `data.assigned_user` ile atanan kişiye başvurun. |
| `CUSTOMER_ERASED` | 409 | Verisi imha edilmiş Hastanın satışında yazma. | Kayıt salt okunurdur. |
| `SALE_NO_CUSTOMER` | 422 | Hastası silinmiş satışa ödeme ekleniyor. | Bu satışa tahsilat eklenemez. |
| `PAYMENT_ADD_FAILED` | 422 | Ödeme kaydedilirken beklenmeyen hata. | Önce `GET /sales/{id}/transactions` ile kaydın oluşup oluşmadığına bakın, sonra tekrar deneyin. |
| `INVOICE_SERIES_LOOKUP_FAILED` | 422 | Seri alınamadı (API anahtarı eksik, entegratöre ulaşılamıyor, E-Fatura hesabı). | Fatura hesabı ayarlarını kontrol edin. |
| `INVOICE_PREVIEW_FAILED` | 422 | Önizleme üretilemedi. | Satış kalemlerini ve döviz kurunu kontrol edin. |
| `INVOICE_CREATE_FAILED` | 422 | Fatura oluşturulamadı. Neden ayrıntısı dönmez. | Aşağıdaki nedenleri kontrol edin. |
| `INVOICE_SEND_FAILED` | 422 | Taslak kesinleştirilemedi, ör. `Bu fatura zaten kesinleştirilmiş.` | `message` metnini okuyun; "zaten kayıtlı" uyarısında `query-status` çağırın. |
| `INVOICE_STATUS_QUERY_FAILED` | 422 | Durum sorgulanamadı, ör. `Fatura henüz e-fatura sistemine gönderilmemiş.` | Taslak ya da gönderilmemiş faturayı sorgulamayın. |
| `SALE_INVOICED` | 422 | Faturalanmış satış siliniyor. | Faturayı iptal etmek satışı `completed` durumuna döndürür; silme kararını bundan sonra verin. |

`INVOICE_CREATE_FAILED` yanıtı gerçek nedeni taşımaz. Şu nedenleri sırayla eleyin:

* Tutarı sıfır olan satış: 0 TL'lik satışa e-SMM kesilemez.
* Yabancı para birimli satışta `exchange_rate` 0'dan büyük değil.
* Fatura hesabında API anahtarı yok ya da hesap türü E-Fatura.
* Lead aşamasındaki Hasta.
* Klinikte stok düşme modu **Fatura Kesildiğinde** ve stok yetersiz. Sunucu bu durumda `Yetersiz stok: <ürün> (Depo No: <depo>)` hatasını üretir; yanıtta yine de yalnızca genel mesaj görürsünüz.

<Warning>
  `POST /sales`, `POST /sales/{id}/payments` ve `POST /invoices` [idempotency anahtarını](/api/istekler/idempotency) desteklemez. Zaman aşımından sonra isteği körlemesine tekrarlarsanız ikinci bir satış, ikinci bir tahsilat ya da ikinci bir fatura oluşabilir. Tekrar etmeden önce `GET /sales?customer_id=123`, `GET /sales/{id}/transactions` ya da `GET /invoices?sale_id=123` ile kaydın oluşup oluşmadığını kontrol edin.
</Warning>

Klinik aboneliği ya da kurulumu nedeniyle kilitliyse bu isteklerin hepsi `402` veya `428` ile döner. Bkz. [Abonelik ve kurulum kilitleri](/api/istekler/erisim-kilitleri).

## İlgili sayfalar

<CardGroup cols={2}>
  <Card title="Satışlar" icon="shopping-cart" href="/api/kaynaklar/satislar">
    Satış nesnesi, durumlar, listeleme ve dışa aktarma.
  </Card>

  <Card title="Hesaplar ve işlemler" icon="landmark" href="/api/kaynaklar/hesaplar-ve-islemler">
    Kasa/banka hesapları, hasta işlemleri ve bakiyeler.
  </Card>

  <Card title="Faturalar" icon="file-text" href="/api/kaynaklar/faturalar">
    Fatura nesnesi, iptal, PDF/XML ve fatura hesapları.
  </Card>

  <Card title="e-Fatura entegrasyonu" icon="plug" href="/api/entegrasyonlar/e-fatura">
    Entegratör hesabı ekleme, seriler ve kontör.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.