> ## 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.

# Abonelik ve faturalama

> Kliniğin Flextell aboneliğini, proforma faturaları, ödemeyi, kullanımı, ek paketleri ve fatura ayarlarını anlatır.

`/v1/billing` kaynağı, kliniğin Flextell'e ne ödediğini ve neleri kullanabildiğini yönetir: abonelik planı, proforma faturalar, kart ödemesi, kullanım ve kota, ek paketler ve fatura bilgileri. Panelde bu ekranlar **Faturalarım** menüsünde bulunur. Panel anlatımı için [Faturalarım](/panel/sistem/faturalarim/genel-bakis) sayfasına bakın.

<Info>
  Bu kaynak, kliniğin **Flextell'e** ödediği abonelik tutarlarını kapsar. Kliniğin hastalarına kestiği faturalar için [Faturalar](/api/kaynaklar/faturalar) sayfasına bakın. Ek paketlerle tanımlanan krediler için [Krediler](/api/kaynaklar/krediler) sayfasına bakın.
</Info>

## Endpoint özeti

Tüm istekler `Authorization: Bearer <access_token>` ve `X-Tenant: <tenant_id>` başlıklarını taşır. Başlıkların anlamı için [Klinikler ve X-Tenant](/api/klinikler-ve-x-tenant) ve [Scope'lar](/api/kimlik-dogrulama/scopelar) sayfalarına bakın. Scope'lar birbirini kapsamaz: `billing:write` taşıyan token `billing:read` uç noktalarını çağıramaz.

| Metot | Endpoint | Açıklama | Scope | İzin |
| - | - | - | - | - |
| GET | `/v1/billing/subscription` | Abonelik durumunu ve yenileme dönemini getirir. | `billing:read` | `View:ProformaInvoice` |
| GET | `/v1/billing/plans` | Satın alınabilir planları ve her plan için yapılabilecek işlemi listeler. | `billing:read` | `View:ProformaInvoice` |
| POST | `/v1/billing/subscription/quote` | Satın alma önizlemesi verir; fatura oluşturmaz. | `billing:read` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/subscription/purchase` | Abonelik satın alma faturası oluşturur veya devam ettirir. | `billing:write` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/subscription/plan-change` | Sonraki dönem için daha düşük plana geçiş faturası oluşturur. | `billing:write` | `Pay:ProformaInvoice` |
| DELETE | `/v1/billing/subscription/plan-change` | Ödenmemiş plan seçimini iptal eder. | `billing:write` | `Pay:ProformaInvoice` |
| GET | `/v1/billing/overview` | Borç, sonraki vade ve dönem tahminini getirir. | `billing:read` | `View:BillingUsage` ve `View:ProformaInvoice` |
| GET | `/v1/billing/proforma-invoices` | Proforma faturaları listeler. | `billing:read` | `View:ProformaInvoice` |
| GET | `/v1/billing/proforma-invoices/{id}` | Tek proforma faturayı satırları, ödemeleri ve `checkout` bilgisiyle getirir. | `billing:read` | `View:ProformaInvoice` |
| GET | `/v1/billing/proforma-invoices/{id}/pdf` | Proforma faturayı PDF olarak indirir. | `billing:read` | `Download:ProformaInvoice` |
| GET | `/v1/billing/payment-providers` | Kullanılabilir ödeme sağlayıcılarını listeler. | `billing:read` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/proforma-invoices/{id}/pay` | Faturanın kalan tutarı için ödeme başlatır. | `billing:write` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/proforma-invoices/{id}/discount-code` | Ödenmemiş faturaya indirim kodu uygular. | `billing:write` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/proforma-invoices/{id}/complete` | Tutarı sıfırlanmış faturayı ödeme olmadan tamamlar. | `billing:write` | `Pay:ProformaInvoice` |
| POST | `/v1/billing/proforma-invoices/{id}/cancel-purchase` | Ödenmemiş abonelik veya ek paket satın almasını iptal eder. | `billing:write` | `Pay:ProformaInvoice` |
| GET | `/v1/billing/payments` | Ödeme denemelerini ve ödemeleri listeler. | `billing:read` | `View:BillingPayment` |
| GET | `/v1/billing/current-usage` | Geçerli dönemin kullanımını getirir. | `billing:read` | `View:BillingUsage` |
| GET | `/v1/billing/usage-history` | Geçmiş dönemlerin kullanımını listeler. | `billing:read` | `View:BillingUsage` |
| GET | `/v1/billing/quota-packages` | Satın alınabilir ek paketleri listeler. | `billing:read` | `View:BillingQuotaPackage` |
| POST | `/v1/billing/quota-packages/{id}/purchase` | Ek paket için ödenmemiş fatura oluşturur. | `billing:write` | `Purchase:BillingQuotaPackage` |
| GET | `/v1/billing/settings` | Fatura ayarlarını getirir. | `billing:read` | `View:TenantBillingSetting` |
| PUT | `/v1/billing/settings` | Fatura e-postasını, unvanı ve vergi bilgilerini günceller. | `billing:write` | `Update:TenantBillingSetting` |
| PUT | `/v1/billing/seats` | Ek kullanıcı sayısını ayarlar. | `billing:write` | `Update:TenantBillingSetting` |
| GET | `/v1/billing/discount-codes` | Uygulanan indirimleri ve bekleyen kodları listeler. | `billing:read` | `View:TenantBillingSetting` |
| POST | `/v1/billing/discount-codes` | Kliniğe indirim kodu tanımlar. | `billing:write` | `Update:TenantBillingSetting` |

### Ortak kurallar

* Tutarlar metin olarak döner (`"9900.00"`). Tek kayıt yanıtları `{"success": true, "data": ..., "meta": {...}}` biçimindedir. Liste yanıtlarında `success` alanı yoktur. Genel yapı için [Yanıt yapısı](/api/istekler/yanit-yapisi) sayfasına bakın.
* Takvim alanları (`issue_date`, `due_date`, `period_start`, `period_end`) `YYYY-MM-DD` biçimindedir. `period_end` dönemin dışında kalan ilk gündür; son dahil gün `period_end` eksi 1 gündür.
* Dönem sınırları, satın alma son ödeme günleri ve yenileme tarihleri klinik saat diliminize göre değil, `Europe/Istanbul` muhasebe saatine göre hesaplanır. Zaman damgası filtreleri (`created_at_*`, `completed_at_*`, `applied_at_*`, `assigned_at_*`) ise klinik saat diliminin gün sınırlarıyla okunur. `is_overdue` ve gecikmiş ödeme kilidi UTC tarihine göre değerlendirilir.
* Plan ve paket fiyatları KDV hariçtir. KDV her satırda `tax_rate` oranıyla ayrıca eklenir.
* Abonelik veya ödeme kilidi varken `subscription`, `plans`, fatura, ödeme, `overview`, `settings` ve `payments` uç noktaları açık kalır; böylece klinik plan alıp borcunu ödeyebilir. `current-usage`, `usage-history`, `quota-packages`, `seats`, `discount-codes` ve `plan-change` uç noktaları kilitliyken `402` döner.
* `billing` uç noktaları kurulum kilidine (`428 SETUP_REQUIRED`) takılmaz. Abonelik ve ödeme kilitleri için [Erişim kilitleri](/api/istekler/erisim-kilitleri) sayfasına bakın.
* Listelerde sayfalama için [Sayfalama](/api/istekler/sayfalama) sayfasına bakın. `per_page` 1-100 arasındadır, varsayılan 15'tir.

## Abonelik durumu

`GET /v1/billing/subscription` aboneliğin hangi aşamada olduğunu döner. `status` alanı beş değerden birini alır.

| `status` | Anlamı | Aşama kuralı |
| - | - | - |
| `demo` | Deneme süresi. | Yeni klinikler deneme planıyla başlar. Varsayılan süre 14 gündür. |
| `active` | Ödenmiş abonelik dönemi sürüyor. | `paid_until` gelecekte. |
| `grace` | Yenileme süresi. | `paid_until` geçti, ancak üzerinden 14 gün geçmedi. |
| `expired` | Süre doldu. | Deneme bitti ya da yenileme süresi doldu. |
| `legacy` | Önceden ödemeli abonelik hiç alınmamış klinik. | Dönem sonunda faturalanır. |

Yanıttaki alanlar:

| Alan | Tür | Açıklama |
| - | - | - |
| `status`, `plan_code`, `plan_name` | metin | Durum ve mevcut plan. |
| `renewal_period` | nesne veya `null` | `start` ve `end`. Yalnızca `active` ve `grace` durumunda dolu. |
| `renewal_notice_days` | sayı | Yenileme bildirimi gün sayısı (7). |
| `pending_plan_code`, `pending_plan_starts_at` | metin | Sonraki dönem için planlanan plan ve başlangıcı. |
| `pending_plan_paid` | boolean | Sonraki dönem plan değişikliğinin ödenip ödenmediği. |
| `demo_expires_at`, `paid_until`, `grace_ends_at` | tarih | Bitiş tarihleri. UTC ISO 8601 biçimindedir. |
| `overage_allowed` | boolean | Kota aşımına izin verilip verilmediği. Yalnızca `active` ve `legacy` için `true`. |
| `can_purchase_extras` | boolean | Ek paket alınıp alınamayacağı. Deneme dışında ve aşıma izin verilen durumlarda `true`. |

<Note>
  `demo_expires_at`, `paid_until`, `grace_ends_at` ve `pending_plan_starts_at` UTC olarak döner. `renewal_period.start` ve `renewal_period.end` ise klinik saat diliminde, ofsetli döner.
</Note>

`GET /v1/billing/overview` borç özetini verir: `subscription`, `outstanding_amount`, `next_due_date`, `current_period_estimate`, `currency` ve `outstanding_by_currency`. Ödenmemiş abonelik ve ek paket satın alma faturaları borca sayılmaz. Bu uç nokta `View:BillingUsage` ve `View:ProformaInvoice` izinlerinin ikisini birden ister.

### Planlar ve plan değişikliği

`GET /v1/billing/plans` etkin ve satılabilir planları döner. Her plan `price` (KDV hariç aylık fiyat), `original_price`, `max_users`, `quotas[]` ve `selection_action` alanlarını taşır. `selection_action` o plan için ne yapabileceğinizi söyler.

| `selection_action` | Ne zaman |
| - | - |
| `request_quote` | Plan self-servis değil. `sales_contact` alanındaki iletişim bilgisi kullanılır. |
| `purchase` | Abonelik `active` değil (deneme, yenileme süresi, süre dolmuş veya `legacy`). |
| `renew` | Mevcut plan `active`. Erken yenileme; `requires_renewal_confirmation` `true` gelir. |
| `schedule_change` | Hedef plan daha ucuz ya da eşit fiyatlı. Sonraki dönem için geçiş. |
| `upgrade` | Hedef plan daha pahalı. Mevcut dönem için kalan süreye göre fark ödenir. |

Satın almadan önce `POST /v1/billing/subscription/quote` ile `plan_code` göndererek tutarı önizleyin. Yanıt faturalanacak satırları, toplamları ve yükseltmede `subscription_upgrade_credit` ile `subscription_upgrade_fraction` değerlerini içerir. Önizleme hiçbir şey yazmaz ve kampanya hakkı tüketmez.

`POST /v1/billing/subscription/purchase` bir `pending_payment` durumunda abonelik faturası oluşturur ve `201` döner. Abonelik, fatura tamamen ödenene kadar değişmez. Kısmi ödeme planı etkinleştirmez.

<ParamField body="plan_code" type="string" required>
  Plan kodu. En fazla 32 karakter.
</ParamField>

<ParamField body="idempotency_key" type="string" required>
  8-128 karakter; `A-Z a-z 0-9 . _ : -`. `Idempotency-Key` başlığı gövdedeki değerin yerine geçer. Aynı anahtar ve plan aynı faturayı döner. Aynı anahtar başka bir planla gelirse `409 PURCHASE_IDEMPOTENCY_CONFLICT` alırsınız. Genel kurallar için [Idempotency](/api/istekler/idempotency) sayfasına bakın.
</ParamField>

Plan değişikliği kuralları:

* Yükseltme `purchase` uç noktasıyla yapılır ve ödeme tamamlanınca plan hemen değişir. Yükseltme teklifi yalnızca plan ve `paid_until` değişmediği sürece geçerlidir.
* Daha ucuz plana geçiş `POST /v1/billing/subscription/plan-change` ile yapılır. Yalnızca `active` durumunda çalışır. Ödeme sonrası yeni plan mevcut dönem bitince başlar.
* Ödenmiş bir sonraki dönem değişikliği (`pending_plan_paid`) varken yeni teklif, satın alma, ödeme veya iptal yapılamaz.
* `DELETE /v1/billing/subscription/plan-change` ödenmemiş plan seçimlerini iptal eder.
* Hedef planın kullanıcı sınırı aktif kullanıcı sayısından düşükse `PLAN_DOWNGRADE_BLOCKED_BY_ACTIVE_USERS` döner.
* Abonelikler iade edilmez. Kullanılmamış ödeme sonraki abonelik faturasında mahsup edilir (`Abonelik mahsubu` satırı).
* Kart ile otomatik tahsilat yoktur. Yenileme için fatura oluşur; ödemeyi siz başlatırsınız.

## Proforma faturalar

Proforma fatura, ödeme öncesi düzenlenen ve mali değeri olmayan belgedir. Ödemeden sonra resmî fatura ayrıca düzenlenir. Faturaları kliniğiniz oluşturmaz, değiştirmez veya silmez; yalnızca okur, öder ya da ödenmemiş satın almaları iptal eder.

### Fatura türleri ve durumları

| `kind` | Etiket | Açıklama |
| - | - | - |
| `period` | `Dönem faturası` | Dönem sonu kullanım faturası. Önceden ödemeli abonelerde yalnızca kota aşımını içerir. |
| `subscription` | `Abonelik satın alımı` | Plan satın alma, yenileme veya yükseltme. |
| `quota_purchase` | `Ek paket alımı` | Ek paket satın alma. |

| `status` | Etiket |
| - | - |
| `draft` | `Taslak` |
| `pending_approval` | `Onay bekliyor` |
| `approved` | `Onaylandı` |
| `rejected` | `Reddedildi` |
| `pending_payment` | `Ödeme bekliyor` |
| `partially_paid` | `Kısmen ödendi` |
| `paid` | `Ödendi` |
| `refunded` | `İade edildi` |
| `cancelled` | `İptal edildi` |

`approved`, `pending_payment` ve `partially_paid` durumları ödenebilir durumlardır. `Onay bekliyor` belgeleri listede görünür ancak ödenemez. Numara `PRF-2026-000123` biçimindedir.

### Listeleme

`GET /v1/billing/proforma-invoices` şu parametreleri alır.

| Parametre | Açıklama |
| - | - |
| `view` | `documents` (ödenmeyi bekleyen satın almalar ve iptaller hariç geçmiş), `purchases` (ödenmemiş abonelik ve ek paket satın almaları), `closed` (iptal edilenler). Verilmezse fatura geçmişi döner. Geçersiz değer `422` döner. |
| `search` | Fatura numarasında büyük/küçük harf duyarsız arama. En fazla 255 karakter. |
| `status`, `kind` | Yukarıdaki değerlerden biri. |
| `issue_date_from`, `issue_date_to` | Düzenlenme tarihi aralığı. `_to` dahildir. |
| `due_date_from`, `due_date_to` | Vade tarihi aralığı. `_to` dahildir. |
| `per_page` | 1-100, varsayılan 15. |
| `sort_by` | `issue_date` (varsayılan), `due_date`, `total_amount`, `number`, `created_at`. |
| `sort_order` | `asc` veya `desc`. `sort_by` ile `sort_order` göndermezseniz `number` A'dan Z'ye, diğer alanlar azalan sıralanır. Genel kurallar için [Filtreleme ve sıralama](/api/istekler/filtreleme-ve-siralama) sayfasına bakın. |

Liste yanıtı satırları (`lines`) içerir ancak `checkout`, `payments` ve `discount_applications` içermez. Süresi dolmuş ama henüz iptal edilmemiş bir ek paket satın alması `purchase_expired: true` ile listelenir.

### Fatura nesnesi

| Alan | Tür | Açıklama |
| - | - | - |
| `id`, `number`, `kind`, `kind_label`, `status`, `status_label` | | Kimlik, numara, tür ve durum. Süresi dolmuş satın almada `status_label` `Süresi doldu` olur. |
| `currency` | metin | Para birimi (`TRY`). |
| `gross_amount`, `discount_amount`, `net_amount`, `tax_amount`, `total_amount` | metin | Tutarlar. |
| `paid_amount`, `outstanding_amount` | metin | Ödenen ve kalan tutar. |
| `is_fully_paid`, `is_overdue`, `is_payable` | boolean | Hesaplanmış durum bayrakları. |
| `is_pending_purchase`, `purchase_expired` | boolean | Ödenmemiş satın alma ve süresinin dolup dolmadığı. |
| `subscription_plan_code`, `is_subscription_upgrade` | metin, boolean | Abonelik faturalarında plan ve yükseltme bilgisi. |
| `issue_date`, `due_date`, `period_start`, `period_end` | tarih | Takvim tarihleri. |
| `lines[]` | dizi | Fatura satırları. |
| `discount_applications[]`, `payments[]` | dizi | Yalnızca tek fatura okumada gelir. |
| `checkout` | nesne | Yalnızca tek fatura okumada gelir. |

Satır alanları: `source`, `billing_type`, `description`, `quantity`, `unit`, `unit_price`, `gross_amount`, `discount_allocated`, `net_amount`, `tax_rate`, `tax_amount`, `line_total`, `period_start`, `period_end`. Yalnızca `Abonelik mahsubu` satırı negatif olabilir.

`checkout` nesnesi hangi düğmeleri göstereceğinizi söyler. Ödeme arayüzünüzü göstermeden önce `GET /v1/billing/proforma-invoices/{id}` çağırın.

| `checkout` alanı | Anlamı |
| - | - |
| `can_pay` | Ödeme başlatılabilir. |
| `can_cancel_purchase` | Satın alma iptal edilebilir. |
| `can_apply_discount` | İndirim kodu uygulanabilir. |
| `can_complete_without_payment` | Toplam 0 ve indirim var; ödemesiz tamamlanabilir. |
| `active_payment_id` | Süren ödeme denemesi. |
| `blocked_error_code`, `blocked_message` | Ödemeyi engelleyen neden. |

`GET /v1/billing/proforma-invoices/{id}/pdf` A4 PDF döner. Dosya adı `{numara}.pdf` biçimindedir ve belge yalnızca Türkçedir. Başka kliniğin faturası `404 PROFORMA_NOT_FOUND` döner.

## Ödeme

Ödeme üç adımda ilerler: sağlayıcıyı seçin, ödemeyi başlatın, sonucu faturadan okuyun.

<Steps>
  <Step title="Sağlayıcıyı seçin">
    `GET /v1/billing/payment-providers` kullanılabilir sağlayıcıları `key`, `name`, `logo_url` ve `is_default` ile listeler. `gateway` göndermezseniz varsayılan sağlayıcı kullanılır.
  </Step>

  <Step title="Ödemeyi başlatın">
    `POST /v1/billing/proforma-invoices/{id}/pay` isteğini gönderin. Yanıttaki `initiation.redirect_url` adresine kullanıcıyı yönlendirin (kart ödeme sayfası).
  </Step>

  <Step title="Sonucu doğrulayın">
    Kullanıcı `return_url` adresine döner. Yanıtı ödeme kanıtı saymayın; `GET /v1/billing/proforma-invoices/{id}` ile `status` ve `paid_amount` değerlerini okuyun.
  </Step>
</Steps>

<ParamField body="gateway" type="string">
  Sağlayıcı anahtarı. Verilmezse varsayılan sağlayıcı.
</ParamField>

<ParamField body="return_url" type="string">
  Ödeme sonrası tarayıcının döneceği `http` veya `https` adresi. En fazla 2048 karakter; izinli bir kaynak adresine ait olmalı, kullanıcı bilgisi ve `#` parçası içermemelidir.
</ParamField>

<ParamField body="billing_email" type="string">
  Kliniğin geçerli bir fatura veya klinik e-postası yoksa zorunludur. Mevcut geçerli adres değiştirilmez.
</ParamField>

Yanıt `payment_id`, `proforma_invoice_id`, `gateway`, `amount`, `currency` ve `initiation` (`type`, `redirect_url` ya da `form_content`, `reference`) alanlarını döner.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://app.flextell.ai/api/v1/billing/proforma-invoices/123/pay \
    -H "Authorization: Bearer <access_token>" \
    -H "X-Tenant: <tenant_id>" \
    -H "Content-Type: application/json" \
    -d '{"return_url": "https://panel.ornek-klinik.com/odeme-sonucu"}'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://app.flextell.ai/api/v1/billing/proforma-invoices/123/pay", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "X-Tenant": tenantId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ return_url: "https://panel.ornek-klinik.com/odeme-sonucu" }),
  });
  const { data } = await res.json();
  window.location.href = data.initiation.redirect_url;
  ```
</CodeGroup>

Ödeme kuralları:

* Kart ödemesi her zaman faturanın **kalan tutarının tamamı** içindir; tek taksit ve TL ile çalışır. Kısmi ödeme yoktur.
* Bir faturada aynı anda tek ödeme denemesi olur. 60 dakikadan yeni bir deneme varken yeni istek `409 PAYMENT_ALREADY_PROCESSED` döner (`data.payment_id`, `data.status`). 60 dakikadan eski deneme başarısız sayılır.
* Sağlayıcı sayfasından dönüşte tarayıcı `return_url` adresine `tenant`, `proforma_invoice_id` ve `payment_attempt` sorgu parametreleriyle yönlendirilir. Doğrulama başarısız olursa `payment_issue=verification_failed` eklenir; bu durumda sonucu `GET /v1/billing/proforma-invoices/{id}` ile faturadan okuyun.
* Süresi dolmuş oturumda gelen başarılı geri dönüş `409 PAYMENT_SESSION_EXPIRED` ile reddedilir ve fatura ödenmemiş kalır.
* Tutar veya para birimi uyuşmazsa deneme başarısız olur (`PAYMENT_AMOUNT_MISMATCH`, `PAYMENT_CURRENCY_MISMATCH`).

### İndirim kodu ve ödemesiz tamamlama

`POST /v1/billing/proforma-invoices/{id}/discount-code` gövdesinde `discount_code` alır (en fazla 64 karakter; büyük harfe çevrilir, `A-Z 0-9 _ -`). Hatalar `422 VALIDATION_FAILED` yanıtında `errors.discount_code` altında gelir. Kod yalnızca ödenebilir, süresi dolmamış, ödenmiş tutarı ve süren ödeme denemesi olmayan faturaya uygulanır. Kampanyalar kod olarak girilemez. Kod, otomatik kampanya indirimini ancak ödenecek toplamı kesin olarak düşürüyorsa değiştirir.

Toplam 0'a inen ve en az bir indirimi olan fatura için `POST /v1/billing/proforma-invoices/{id}/complete` çağırın. Fatura `paid` olur, abonelik ya da paket hemen etkinleşir ve ödeme kaydı oluşmaz. Tutarı sıfır olmayan fatura için `PROFORMA_NOT_PAYABLE` döner. Sıfır tutarlı faturada `pay` çağırırsanız `PROFORMA_ALREADY_PAID` alırsınız.

### Satın almayı iptal etme

`POST /v1/billing/proforma-invoices/{id}/cancel-purchase` yalnızca ödenmemiş abonelik veya ek paket satın almasını iptal eder (`pending_payment`, `paid_amount` 0, ödeme denemesi yok). Uygulanan indirimler geri verilir. Dönem faturaları, kısmen ödenmiş ya da ödeme işlenen satın almalar `409 PURCHASE_NOT_CANCELLABLE` döner.

### Ödemeleri listeleme

`GET /v1/billing/payments` ödeme denemelerini döner. Filtreler: `status` (`pending`, `authorized`, `success`, `failed`, `refunded`, `partially_refunded`), `method` (`psp`, `bank_transfer`, `cash`, `cheque`, `offset`), `proforma_invoice_id`, `completed_at_from`, `completed_at_to`, `created_at_from`, `created_at_to`. Sıralama: `sort_by` `created_at` (varsayılan), `completed_at` veya `amount`. Yanıtta `masked_reference` (son 4 karakter dışında maskeli) ve başarısız ödemelerde güvenli bir `failure_message` bulunur.

## Kullanım ve kotalar

Kullanım uç noktaları `View:BillingUsage` izni ister.

`GET /v1/billing/current-usage` geçerli dönemin kullanımını döner. `usage[]` her zaman aynı sırada yedi satır içerir: `subscription_fee`, `seat`, `ai_chat`, `ai_report`, `whatsapp`, `sms`, `storage`.

| `usage[]` alanı | Açıklama |
| - | - |
| `billing_type`, `billing_type_label` | Kalem türü ve etiketi. |
| `is_measurable` | Ölçülemediğinde `false` ve kullanım sıfır döner; hata verilmez. |
| `used`, `unit`, `unit_label` | Kullanım ve birimi. |
| `included`, `credits`, `effective_quota`, `remaining`, `overage` | Plan kotası, ek paket kredisi, geçerli kota, kalan ve aşım. |
| `utilisation_percent` | Kullanım yüzdesi. Kota yoksa `null`; 100'ü aşabilir. |
| `quota_source` | `override` (`Firmaya özel kota`), `plan` (`Plan kotası`) veya `none` (`Kota tanımlı değil`). |
| `estimated_amount` | Tahmini tutar. Deneme kliniklerde ve önceden ödenmiş abonelik/ek kullanıcı satırlarında 0'dır. |

Yanıtta ayrıca `period` (`start`, `end`, `label`), `billing_plan_code`, `estimated_total`, `ai_role_costs` ve `ai_role_costs_in_billing_currency` alanları bulunur.

Kalem türleri ve birimleri:

| `billing_type` | Etiket | Ölçü |
| - | - | - |
| `ai_chat` | `Yapay zekâ sohbeti` | Sağlayıcı maliyeti, ₺ |
| `ai_report` | `Yapay zekâ raporu` | Sağlayıcı maliyeti, ₺ |
| `whatsapp` | `WhatsApp mesajı` | Giden mesaj sayısı |
| `sms` | `SMS` | Mesaj sayısı |
| `storage` | `Depolama` | Dönem boyunca ortalama kullanılan alan, GB/ay |
| `seat` | `Ek kullanıcı` | Ek kullanıcı sayısı |
| `subscription_fee` | `Abonelik ücreti` | Dönem |

`GET /v1/billing/usage-history` geçmiş dönemleri, en yeni dönem önce olacak şekilde döner. Yeniden hesaplanarak yerine yenisi konan dönemler listelenmez. Filtreler: `billing_type`, `period_start_from`, `period_start_to`, `per_page`; `sort_order` `period_start` üzerinde çalışır (varsayılan `desc`). Her kayıt `period_start`, `period_end`, `status`, `is_shadow`, `billing_plan_code`, `usage[]` ve ilgili `proforma_invoice` alanlarını taşır. `is_shadow: true` olan dönemler hiçbir zaman faturalanmaz.

### Kota aşımı davranışı

Davranış aboneliğin durumuna göre değişir.

| Durum | Kota dolunca |
| - | - |
| `active`, `legacy` | Hizmet durmaz. Aşan kullanım dönem faturasına ek kalem olarak yansır. |
| `demo`, `grace` | Kota sert sınırdır. İlgili özellik `422 QUOTA_EXHAUSTED` (`data.billing_type`) ile durur; diğer özellikler çalışır. |
| `expired` | Ürün uç noktaları `402 SUBSCRIPTION_REQUIRED` döner. |

Kota %80 ve %100'e ulaşınca klinik bilgilendirilir. Depolamada, ücretsiz kotayı aşmak yalnızca aşım üretir; üst sınıra ulaşıldığında yükleme `STORAGE_HARD_LIMIT_EXCEEDED` ile reddedilir.

## Ek paketler

Ek paket, plan kotasının üstüne satın alınan kullanım hakkıdır. Satın almak için abonelik `active` (veya `legacy`) olmalı, deneme kullanılmamalıdır (`can_purchase_extras: true`). Aksi hâlde `422 SUBSCRIPTION_REQUIRED` alırsınız.

`GET /v1/billing/quota-packages` kliniğin planına uygun etkin paketleri döner (liste sayfalanmaz). `billing_type` ile filtrelenir.

| Alan | Açıklama |
| - | - |
| `id`, `code`, `name`, `description` | Paket bilgisi. |
| `billing_type`, `quantity`, `unit` | Hangi kalem, ne kadar ve hangi birimde. |
| `price`, `tax_rate`, `tax_amount`, `total_price`, `currency` | Net fiyat, KDV ve KDV dahil toplam. |
| `validity_days` | Geçerlilik süresi. `null` ise süresizdir. |
| `pending_purchase` | Ödenmemiş satın alma. Yalnızca `View:ProformaInvoice` izni varsa gelir. |

Ek paket satın alma iki adımdır.

<Steps>
  <Step title="Satın almayı başlatın">
    `POST /v1/billing/quota-packages/{id}/purchase` isteğini `Idempotency-Key` ile gönderin. Yanıt `201` ve `ödeme bekliyor` durumunda bir `quota_purchase` faturasıdır. Bu çağrı ödeme sağlayıcısına gitmez.
  </Step>

  <Step title="Faturayı ödeyin">
    Dönen faturanın `id` değeriyle `POST /v1/billing/proforma-invoices/{id}/pay` çağırın. Ödeme için `Pay:ProformaInvoice` izni de gerekir.
  </Step>
</Steps>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://app.flextell.ai/api/v1/billing/quota-packages/123/purchase \
    -H "Authorization: Bearer <access_token>" \
    -H "X-Tenant: <tenant_id>" \
    -H "Idempotency-Key: ek-paket-2026-10-13-001"
  ```
</CodeGroup>

Kurallar:

* Aynı anahtar ve aynı paket aynı faturayı (`201`) döner. Aynı anahtar başka pakette `409 PURCHASE_IDEMPOTENCY_CONFLICT` verir. Yeni anahtar her zaman yeni bir satın alma oluşturur.
* Paket kliniğin planında sunulmuyorsa `QUOTA_PACKAGE_NOT_AVAILABLE_FOR_PLAN`; paket bulunamazsa veya kredi havuzuna çevrilemezse `QUOTA_PACKAGE_NOT_FOUND` döner.
* Vade, düzenlenme tarihine ödeme süresi (varsayılan 14 gün) eklenerek belirlenir. Vadeyi geçen ödenmemiş satın alma `Süresi doldu` olur, ödenemez (`PROFORMA_NOT_PAYABLE`) ve otomatik iptal edilir.
* Ödeme tamamlanınca kredi bir kez tanımlanır. Kredi, ödeme anından `validity_days` süresince geçerlidir. AI paketleri satın alınan türe (`ai_chat` veya `ai_report`) bağlıdır. Krediler yalnızca plan kotasını aşan kullanımda, en eski kredi önce olmak üzere tüketilir; depolama kredisi günlük sınırı yükseltir.
* Ödenmemiş ek paket satın almaları borç sayılmaz, hatırlatılmaz ve erişimi kilitlemez.

## Fatura ayarları

`GET /v1/billing/settings` ve `PUT /v1/billing/settings` fatura bilgilerini yönetir. Hiç ayar kaydedilmemiş klinik için varsayılan değerler kayıt oluşturmadan döner; ilk `PUT` kaydı oluşturur.

| Alan | Tür | Güncellenebilir | Açıklama |
| - | - | - | - |
| `billing_email` | e-posta veya `null` | Evet (en fazla 255) | Fatura e-postası. Boşsa klinik e-postası kullanılır. |
| `legal_name_override` | metin veya `null` | Evet (en fazla 255) | Fatura unvanı. |
| `tax_number_override` | metin veya `null` | Evet (en fazla 32) | Vergi numarası. |
| `tax_office_override` | metin veya `null` | Evet (en fazla 255) | Vergi dairesi. |
| `extra_seats` | sayı | Evet (0-500) | Ek kullanıcı sayısı. `null` kabul edilmez. |
| `effective_legal_name`, `effective_tax_number`, `effective_tax_office`, `effective_billing_email` | metin | Hayır | Geçersiz kılma yoksa klinik bilgisine düşen etkin değerler. |
| `billing_plan_code`, `billing_plan_name`, `payment_term_days`, `is_billing_enabled` | | Hayır | Plan ve ödeme koşulları. |
| `plan_max_users`, `max_users_override`, `effective_max_users` | sayı | Hayır | Kullanıcı sınırı. |
| `billing_day`, `billing_started_at`, `storage_hard_limit_bytes`, `overage_alert_amount` | | Hayır | Flextell tarafından yönetilen alanlar. |

<Note>
  Bu uç nokta yalnızca yukarıda "Evet" yazan alanları değiştirir. Diğer alanları gönderseniz de sessizce yok sayılır. Alanı `null` göndererek geçersiz kılmayı temizler, göndermediğiniz alan değişmez. Güncelleme tek işlem olarak yapılır; ek kullanıcı hatası varsa tüm istek geri alınır.
</Note>

### Ek kullanıcılar

`PUT /v1/billing/seats` gövdesinde `extra_seats` alır (0-500). Yanıt `extra_seats`, `plan_max_users`, `max_users_override`, `previous_extra_seats`, `effective_max_users` ve `charged_from` alanlarını döner. Kullanıcı sınırı hemen artar: sınır, planın (veya geçersiz kılmanın) kullanıcı sayısı artı ek kullanıcılardır.

* Değer değişmiyorsa işlem hata vermez; deneme kliniğinde bile kabul edilir.
* Değişiklik için abonelik `active` veya `legacy` olmalı ve gecikmiş ödeme kilidi olmamalıdır. Aksi hâlde `SUBSCRIPTION_REQUIRED` (422) veya `ACCESS_RESTRICTED_BY_OVERDUE_PAYMENT` (402) alırsınız.
* Sayıyı aktif kullanıcı sayısının altına indirirseniz `422 SEAT_REDUCTION_BLOCKED_BY_ACTIVE_USERS` döner (`data.active_users`, `data.limit`).
* Ücretlendirme `charged_from` tarihinden başlar (sonraki yenileme ya da mevcut fatura döneminin sonu). Önceden ödemeli kliniklerde yenileme, ödenen dönemde ulaşılan en yüksek ek kullanıcı sayısını faturalar.

### İndirim kodları

`GET /v1/billing/discount-codes` uygulanmış indirimleri (`data`) ve henüz kullanılmamış tanımlamaları (`pending_assignments`) iki ayrı sayfalamayla döner (`page`/`per_page` ve `pending_page`/`pending_per_page`). `applied_at_from`, `applied_at_to`, `assigned_at_from` ve `assigned_at_to` filtreleri günlük sınırlarla çalışır.

`POST /v1/billing/discount-codes` gövdesinde `code` alır (en fazla 64 karakter; kırpılır ve büyük harfe çevrilir). Kod kliniğe `pending` durumda tanımlanır (`201`); kullanım hakkı bu çağrıda düşmez. Bir faturaya kod uygulamak için yukarıdaki fatura uç noktasını kullanın.

## Hata kodları

Tüm hata yanıtları `{"success": false, "error_code": ..., "message": ...}` biçimindedir. Genel kodlar için [Hata kodları](/api/istekler/hata-kodlari) sayfasına bakın. Bu kaynağa özgü başlıca kodlar:

| Kod | HTTP | Ne zaman |
| - | - | - |
| `SUBSCRIPTION_REQUIRED` | 402 | Deneme veya abonelik süresi doldu. `data` alanı abonelik özetini taşır. |
| `SUBSCRIPTION_REQUIRED` | 422 | Deneme, yenileme süresi veya süresi dolmuş abonelikte ek paket satın alma ya da ek kullanıcı değişikliği. |
| `ACCESS_RESTRICTED_BY_OVERDUE_PAYMENT` | 402 | Vadesi geçmiş dönem faturası (`data.proforma_invoice_id`, `data.due_date`). Vadeden **bir gün sonra** başlar, ödeme anında kalkar. |
| `QUOTA_EXHAUSTED` | 422 | Deneme veya yenileme süresinde kota doldu. |
| `BILLING_PLAN_NOT_FOUND` | 422 | Plan etkin değil, satılamaz veya fiyatı yok. |
| `SUBSCRIPTION_CHANGE_NOT_AVAILABLE` | 422, 409 | Plan değişikliği uygulanamıyor, ödenmiş sonraki dönem değişikliği var, yükseltme teklifi geçersiz veya başka plan için ödeme sürüyor (409). |
| `PLAN_DOWNGRADE_BLOCKED_BY_ACTIVE_USERS` | 422 | Aktif kullanıcı sayısı hedef planın sınırını aşıyor. |
| `SEAT_REDUCTION_BLOCKED_BY_ACTIVE_USERS` | 422 | Ek kullanıcı sayısı aktif kullanıcıların altına indirilemez. |
| `PURCHASE_IDEMPOTENCY_CONFLICT` | 409 | Aynı anahtar başka bir plan veya pakette kullanıldı. |
| `PROFORMA_NOT_FOUND` | 404 | Fatura yok ya da başka bir kliniğe ait. |
| `PROFORMA_NOT_PAYABLE` | 422 | Fatura ödenebilir durumda değil veya süresi doldu. |
| `PROFORMA_ALREADY_PAID` | 422 | Fatura zaten tamamen ödenmiş. |
| `PURCHASE_NOT_CANCELLABLE` | 409 | Satın alma artık iptal edilemiyor. |
| `PAYMENT_ALREADY_PROCESSED` | 409 | Başka bir ödeme denemesi sürüyor. |
| `PAYMENT_BUYER_EMAIL_REQUIRED` | 422 | Geçerli bir fatura e-postası yok; `billing_email` gönderin. |
| `PAYMENT_GATEWAY_UNAVAILABLE` | 503 | Ödeme sağlayıcısı kullanılamıyor. |
| `PAYMENT_INITIATION_FAILED` | 502 | Ödeme başlatılamadı. |
| `QUOTA_PACKAGE_NOT_FOUND` | 404, 422 | Paket yok veya kredi havuzuna çevrilemiyor. |
| `QUOTA_PACKAGE_NOT_AVAILABLE_FOR_PLAN` | 422 | Paket kliniğin planında sunulmuyor. |
| `DISCOUNT_CODE_NOT_FOUND` | 404 | `POST /v1/billing/discount-codes` ile tanımlanan kod bulunamadı. Faturaya kod uygularken hatalar `422 VALIDATION_FAILED` ile `errors.discount_code` altında gelir. |
| `DISCOUNT_CODE_EXPIRED` | 422 | Kod etkin değil ya da geçerlilik aralığı dışında. |
| `DISCOUNT_CODE_EXHAUSTED` | 422 | Kodun kullanım sınırı doldu. |
| `DISCOUNT_CODE_ALREADY_USED` | 422 | Kod kliniğe zaten tanımlı ya da tek kullanımlık kod kullanıldı. |

## Yetki

Faturalama izinleri klinik geneli için geçerlidir; kayıt sahipliğine göre sınırlama yoktur. İzin matrisi için [İzinler ve görünürlük](/api/izinler-ve-gorunurluk) sayfasına bakın.

| Amaç | Gerekli izin |
| - | - |
| Abonelik, plan, fatura listesi ve detayı | `View:ProformaInvoice` |
| Fatura PDF | `Download:ProformaInvoice` |
| Teklif, satın alma, plan değişikliği, ödeme, indirim ve iptal | `Pay:ProformaInvoice` |
| Ödemeleri listeleme | `View:BillingPayment` |
| Kullanım | `View:BillingUsage` |
| Ek paketleri listeleme | `View:BillingQuotaPackage` |
| Ek paket satın alma | `Purchase:BillingQuotaPackage` (ödeme için ayrıca `Pay:ProformaInvoice`) |
| Fatura ayarları ve indirim kodlarını okuma | `View:TenantBillingSetting` |
| Fatura ayarlarını, ek kullanıcıları ve indirim kodu tanımını değiştirme | `Update:TenantBillingSetting` |


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