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

# Randevular

> Randevu oluşturmayı, listelemeyi, güncellemeyi, iptal etmeyi, tamamlamayı ve silmeyi anlatır.

Randevu kaynağı, kliniğin rezervasyon kayıtlarını yönetir: bir hasta, bir doktor, bir başlangıç zamanı ve randevunun tedavi/seans planı. Bu sayfa tek tek randevu işlemlerini anlatır. Takvim akışı ve uygun saatler için [Randevu uygunluğu ve takvim](/api/kaynaklar/randevu-uygunlugu-ve-takvim), doktor zaman aralığını toplu taşımak için [Toplu randevu taşıma](/api/kaynaklar/toplu-randevu-tasima), hatırlatmalar için [Randevu hatırlatmaları](/api/kaynaklar/randevu-hatirlatmalari) sayfasına bakın.

Tüm istekler `https://app.flextell.ai/api/v1` altındadır ve `Authorization: Bearer <access_token>` ile `X-Tenant: <tenant_id>` başlıklarını gerektirir.

## Endpoint özeti

| Metot | Endpoint | Açıklama | Scope | İzin |
| - | - | - | - | - |
| `GET` | `/appointments` | Randevuları listeler | `appointments:read` | `View:Appointment` |
| `GET` | `/appointments/summary` | Bugünün randevu sayıları | `appointments:read` | `View:Appointment` ve `ViewAllAppointments:Appointment` |
| `POST` | `/appointments` | Randevu oluşturur | `appointments:write` | `Create:Appointment` |
| `GET` | `/appointments/{id}` | Randevu detayını getirir | `appointments:read` | `View:Appointment` |
| `PUT` | `/appointments/{id}` | Randevuyu günceller | `appointments:write` | `Update:Appointment` (durum değişiminde ek izin) |
| `POST` | `/appointments/{id}/cancel` | Randevuyu iptal eder | `appointments:write` | `Cancel:Appointment` |
| `POST` | `/appointments/{id}/revert-cancel` | İptali geri alır | `appointments:write` | `RevertCancel:Appointment` |
| `POST` | `/appointments/{id}/complete` | Randevuyu tamamlar, kullanılan ürünleri kaydeder | `appointments:write` (+ `sales:write`) | `Update:Appointment` (+ satış izni) |
| `GET` | `/appointments/{id}/sale-items` | Randevudan satış kalemleri üretir | `appointments:read` ve `sales:write` | `View:Appointment` ve `Create:Sale` |
| `GET` | `/appointments/{id}/deletion-relations` | Silmeyle birlikte silinecek kayıtları gösterir | `appointments:read` | `View:Appointment` |
| `DELETE` | `/appointments/{id}` | Randevuyu siler | `appointments:write` | `Delete:Appointment` |

Randevu formu için doktor, oda, asistan, ürün ve tedavi seçenekleri `GET /appointments/options/*` altındadır. Bu endpoint'ler `Create:Appointment` veya `Update:Appointment` izninden birini yeterli sayar; `View:Doctor` gibi ayrı izinler gerekmez. Randevu silme için ayrı bir scope yoktur, `appointments:write` kullanılır.

<Info>
  `ViewAllAppointments:Appointment` iznine sahip olmayan kullanıcı yalnızca kendi randevularını görür ve değiştirir: randevunun doktoru olduğu veya hastanın lead'inin kendisine atandığı kayıtlar. Asistan olarak eklenmek sahiplik sayılmaz. Görünmeyen veya başka kliniğe ait bir `id` için `403` değil, `404 RESOURCE_NOT_FOUND` döner. Ayrıntı için [İzinler ve görünürlük](/api/izinler-ve-gorunurluk).
</Info>

### Listeleme

`GET /appointments` genel [sayfalama](/api/istekler/sayfalama) ve [filtreleme ve sıralama](/api/istekler/filtreleme-ve-siralama) kurallarını izler. Bu kaynağa özgü olanlar:

| Parametre | Açıklama |
| - | - |
| `search` | En çok 255 karakter. Her sözcük ön ek olarak aranır ve hepsi eşleşmelidir. Hasta adı ve telefonu, doktor, asistanlar, `code` ve `description` alanlarında arar. |
| `sort_by` | `scheduled_at` (varsayılan, azalan), `status`, `created_at`, `updated_at`, `upcoming`. Bilinmeyen değer `422` döner. |
| `sort_order` | `asc` veya `desc`. `sort_by` verip bunu vermezseniz azalan sıralanır. |
| `status`, `relation_type`, `session_type` | Durum, ana/seans randevusu ve seans türü filtresi. `session_type=operation` ana randevuları (kontrol randevuları dahil) verir. |
| `customer_id`, `lead_id`, `user_id`, `assistant_id`, `room_id` | Hasta, lead, doktor, asistan ve oda filtresi. `lead_id` size görünür bir lead olmalıdır; aksi hâlde `422`. |
| `parent_appointment_id`, `is_control_appointment`, `is_ai_generated`, `has_sale` | Üst randevu, kontrol, AI tarafından oluşturulma ve satış varlığı filtresi. |
| `tags[]`, `treatments[]` | Verilen kimliklerden herhangi biriyle eşleşir. |
| `scheduled_at_from`, `scheduled_at_to` | Saat gönderseniz bile klinik saatine göre gün başına ve gün sonuna çekilir. |
| `created_at_from`, `created_at_to` | Yalnızca tarih verirseniz gün başı/sonu, tam zaman damgası verirseniz verdiğiniz an kullanılır. |

`sort_by=upcoming` yaklaşan randevuları en yakından başlayarak, ardından geçmiş randevuları en yeniden başlayarak sıralar. `sort_order` yok sayılır ve arama sıralamasının önüne geçer.

## Nesne modeli

Yanıtlardaki tüm zaman damgaları klinik saat dilimiyle ve sapma değeriyle gelir (`2026-10-20T14:30:00+03:00`). Gönderdiğiniz zaman sapma içermiyorsa klinik saati olarak okunur.

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Randevu kimliği. |
| `code` | string | Otomatik üretilen kod (`APT-XXXXXXXXXX`). |
| `relation_type` | string | `parent` (Ana Randevu) veya `child` (Seans Randevusu). |
| `status` | string | Randevu durumu, bkz. aşağıdaki Durum akışı bölümü. |
| `scheduled_at` | string | Başlangıç zamanı. |
| `duration_minutes` | integer veya null | 5–1440 dakika. `null` ise klinik varsayılan slot süresi kullanılır. |
| `description` | string | Serbest metin, en çok 65000 karakter. |
| `cancellation_reason` | string veya null | İptal nedeni. İptal geri alınınca temizlenir. |
| `customer_id`, `customer` | integer, nesne | Hasta. Size atanmamış bir lead'e aitse maskelenir (`customer.is_masked: true`). |
| `doctor` | nesne | `{id, name}`. |
| `assistants` | dizi | `{id, name}` nesneleri; her zaman dizi gelir. |
| `room_id`, `room` | integer, nesne | Oda. |
| `channel_id` | integer veya null | Hastaya randevu mesajı gidecek kanal. |
| `parent_appointment_id`, `child_appointments` | integer, dizi | Seans randevularında üst randevu; ana randevuda alt randevular. |
| `treatments` | dizi | Randevudaki tedaviler. |
| `treatment_session_plans` | dizi | `{treatment_id, sessions[]}`: tedavi başına planlı seanslar. |
| `linked_sessions` | dizi | Bu randevuyla karşılanan seanslar. |
| `tags` | dizi | Randevu etiketleri. |
| `is_control_appointment` | boolean | Kontrol randevusu. Oluşturulduktan sonra değişmez. |
| `is_ai_generated` | boolean | AI asistan tarafından oluşturulduysa `true`. API ile oluşturulan randevuda her zaman `false`. |
| `sale_id`, `has_sale` | integer, boolean | Randevunun satışı. |
| `pending_scheduled_at`, `pending_expires_at` | string veya null | Toplu taşıma önerisi ve bekletme süresi sonu. |
| `record_state` | nesne | `{is_read_only, reason_code}`. `reason_code`: `CUSTOMER_ERASED` veya `LEAD_NOT_ASSIGNED`. |
| `reminders`, `import_source` | dizi, nesne | Yalnızca detay yanıtında. |
| `customer_balance` | nesne veya null | Yalnızca `GET /appointments/{id}` yanıtında: `{outstanding_balance, overdue_balance, currency_code}`. Yalnızca `View:CustomerBalances` (Görüntüleme: Bakiyeler) izni olan ve hastası size maskeli olmayan kullanıcıya verilir; aksi hâlde alan yanıtta kalır ama `null` döner. |

Liste yanıtı `treatment_session_plans`, `linked_sessions`, `reminders`, `import_source` ve `customer_balance` alanlarını içermez. `GET /appointments/{id}` ayrıca `customer.notification_channels` bloğunu döndürür. Detay yanıtında `customer_balance`, `View:CustomerBalances` izniniz yoksa `null` döner.

## Durum akışı

Randevu durumları: `pending` (Bekliyor), `approved` (Onaylandı), `cancelled` (İptal Edildi), `rejected` (Reddedildi), `completed` (Tamamlandı), `no_show` (Gelmedi).

Zorunlu bir geçiş grafiği yoktur; `PUT /appointments/{id}` ile her duruma geçilebilir. Üç istisna vardır:

```mermaid theme={null}
flowchart LR
    A["Herhangi bir durum"] -- "cancel" --> B["İptal Edildi"]
    B -- "revert-cancel" --> C["Bekliyor / Onaylandı"]
```

| Geçiş | Gereken izin |
| - | - |
| Oluştururken `cancelled` vermek | Kabul edilmez. `422`: `Randevu iptal statüsünde oluşturulamaz; önce oluşturup ardından iptal edin.` |
| `cancelled` durumuna geçiş | `POST …/cancel` için `Cancel:Appointment`. `PUT` ile `Update:Appointment` ve `Cancel:Appointment`. |
| `cancelled` durumundan çıkış | `POST …/revert-cancel` için `RevertCancel:Appointment`. `PUT` ile `Update:Appointment` ve `RevertCancel:Appointment`. |
| Diğer tüm geçişler | Yalnızca `Update:Appointment`. |

Eksik izin `403` döner. Durum değişiminin yan etkileri: iptalde ve reddedildiğinde takvim etkinliği ile randevu hatırlatmaları silinir; iptalden dönüşte yeniden oluşturulur. `approved` durumuna geçince bekleyen randevu hatırlatmaları otomatik onaylanır.

## Oluşturma

`POST /appointments` yeni randevuyu `201` ile döndürür.

| Alan | Zorunlu | Açıklama |
| - | - | - |
| `customer_id` veya `lead_id` | Biri zorunlu | İkisini birlikte göndermeyin. `lead_id` ile gönderirseniz randevu lead'in hasta kaydına bağlanır; lead'in hasta kaydı yoksa oluşturulur. |
| `user_id` | Evet | Doktor. Kliniğin kullanıcısı olmalıdır. |
| `treatments[]` | Evet | En az bir, tekrarsız tedavi; hepsi seçilen doktora atanmış olmalıdır. Seans doldurulurken (`parent_session_id`) zorunlu değildir. |
| `status` | Evet | `cancelled` hariç herhangi bir durum. |
| `scheduled_at` | Evet | Başlangıç zamanı. |
| `duration_minutes` | Hayır | 5–1440. |
| `assistant_ids[]` | Hayır | Aktif asistanlar. Eski `assistant_id` alanı kullanımdan kalkmıştır; ikisi birleştirilir. |
| `room_id`, `tags[]`, `description` | Hayır | Oda, etiketler, açıklama. |
| `channel_id`, `channel_identifier` | Hayır | Bildirim kanalı. Kanal aktif ve bağlı olmalı; hasta o kanalda ulaşılabilir olmalı veya `channel_identifier` (WhatsApp telefonu, Telegram sohbet kimliği, Instagram IGSID) gönderilmelidir. |
| `send_message` | Hayır | Hastaya oluşturma mesajı gönderilsin mi. Boş bırakırsanız kliniğin `send_on_create` ayarı geçerlidir. Başlangıç zamanı geçmişteyse veya ulaşılabilir kanal yoksa mesaj gönderilmez. |
| `is_control_appointment` | Hayır | `true` ise sunucu planı tedavi başına tek bir kontrol seansıyla değiştirir. |
| `treatment_session_plans` | Hayır | Gönderirseniz seansları (ve ürünleri) siz belirlersiniz; göndermezseniz seanslar tedavi şablonundan üretilir. |

`channel_id` göndermezseniz sunucu kanalı seçer ve randevuya yazar: hastanın en son yazdığı kanal, hastanın varsayılan kanalı, kliniğin varsayılan bildirim kanalı, ardından ulaşılabilir herhangi bir kanal.

<Note>
  Manuel randevu geçmiş tarih, `max_future_days` sonrası, kapalı gün, çalışma saati dışı, slot ızgarası dışı bir dakika, tatil veya doktorun başka randevusuyla çakışma nedeniyle reddedilmez. Bunlar istemcilerde yalnızca uyarıdır. Uygun saatleri [Randevu uygunluğu ve takvim](/api/kaynaklar/randevu-uygunlugu-ve-takvim) sayfasından alın.
</Note>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://app.flextell.ai/api/v1/appointments \
    -H "Authorization: Bearer <access_token>" \
    -H "X-Tenant: <tenant_id>" \
    -H "Content-Type: application/json" \
    -d '{
      "customer_id": 123,
      "user_id": 45,
      "treatments": [7],
      "status": "pending",
      "scheduled_at": "2026-10-20T14:30:00+03:00",
      "duration_minutes": 30,
      "description": "İlk muayene",
      "send_message": true
    }'
  ```
</CodeGroup>

### Seans randevusu

Mevcut bir tedavi planının seansını doldurmak için `parent_appointment_id` ile `parent_session_id` birlikte gönderilir. Seans üst randevuya ait ve boş olmalı; hasta üst randevunun hastası olmalıdır. Seans randevusu doktoru, odayı, bildirim kanalını ve süreyi (siz göndermezseniz) üst randevudan alır. `user_id` doğrulanır ama kullanılmaz. Etiket, asistan, `is_control_appointment` ve `cancellation_reason` seans randevusuna uygulanmaz. `products[]` yalnızca `parent_session_id` ile gönderilir; seansın planlı ürünlerini değiştirir, `[]` temizler, göndermemek korur.

## Güncelleme

`PUT /appointments/{id}` güncel randevuyu döndürür. Tüm alanlar isteğe bağlıdır; yalnızca gönderdiğiniz anahtarlar değişir.

* `scheduled_at: null` veya `""` yok sayılır; mevcut zaman korunur.
* `customer_id` yalnızca alt randevusu olmayan ana randevuda değişir. `parent_appointment_id` ve `is_control_appointment` oluşturulduktan sonra değiştirilemez.
* `treatments[]` tedavi kümesini değiştirir. `treatment_session_plans` listelenen tedavilerin seanslarını değiştirir; bir alt randevuyla alınmış seanslar bağlantısını ve tarihini korur. Göndermediğiniz planlara dokunulmaz.
* `tags`, `assistant_ids` ve `assistant_id` anahtarını gönderirseniz tüm küme değişir; boş liste veya `null` hepsini kaldırır.
* `channel_id: null` otomatik kanal seçimine döner.
* Güncelleme mesajı (`send_message` boşsa `send_on_update` ayarı) yalnızca tarih/saat, doktor veya tedavi kümesi değiştiyse ve randevu `cancelled`/`rejected` değilse gönderilir.
* Bir toplu taşıma önerisi beklerken `scheduled_at` değerini farklı bir dakikaya taşırsanız öneri iptal edilir. Aynı dakikayı başka biçimde göndermek öneriyi korur.

## İptal ve iptali geri alma

`POST /appointments/{id}/cancel` yalnızca `Cancel:Appointment` ister; `Update:Appointment` gerekmez.

| Alan | Zorunlu | Açıklama |
| - | - | - |
| `cancellation_reason` | Hayır | En çok 1000 karakter. |

`POST /appointments/{id}/revert-cancel` yalnızca `RevertCancel:Appointment` ister.

| Alan | Zorunlu | Açıklama |
| - | - | - |
| `status` | Evet | `pending` veya `approved`. İptal nedeni temizlenir. |

İki endpoint de güncel randevuyu döndürür. İptalde `cancellation_reason` gönderirseniz bir [iptal takibi](/api/kaynaklar/randevu-hatirlatmalari) hatırlatması sıraya alınır; neden göndermezseniz alınmaz.

```bash curl theme={null}
curl -X POST https://app.flextell.ai/api/v1/appointments/123/cancel \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{"cancellation_reason": "Hasta tarih değiştirmek istedi"}'
```

| Kod | HTTP | Ne zaman |
| - | - | - |
| `APPOINTMENT_ALREADY_CANCELLED` | 409 | İptal edilmiş randevuyu tekrar iptal ettiniz. `Bu randevu zaten iptal edilmiş.` |
| `APPOINTMENT_NOT_CANCELLED` | 409 | İptal edilmemiş randevuda `revert-cancel` çağırdınız. `Yalnızca iptal edilmiş bir randevu geri alınabilir.` |
| `LEAD_NOT_ASSIGNED` | 403 | Randevu, size atanmamış bir lead'in hastasına ait. `data.assigned_user` lead'in sahibini (`{id, name}`) veya `null` verir. |
| `CUSTOMER_ERASED` | 409 | Hastanın verileri imha edilmiş; kayıt salt okunurdur. |

## Tamamlama ve satış kalemleri

`POST /appointments/{id}/complete` tek bir işlemde seanslarda kullanılan ürünleri kaydeder, durumu `completed` yapar ve istenirse satış oluşturur. Herhangi bir adım başarısız olursa hiçbir şey değişmez. Tamamlanınca sonraki seans için onay hatırlatmaları planlanır.

| Alan | Zorunlu | Açıklama |
| - | - | - |
| `sessions[].session_id` | Evet | Bu randevuya bağlı seans; tekrarsız olmalı. Kimlikleri `linked_sessions` alanından alın. |
| `sessions[].products` | Evet | Seansın ürün satırları. Dizi mutlaka bulunmalı; boş dizi seansın ürünlerini temizler. Bir ürün seansta bir kez yer alabilir. |
| `sessions[].products[].product_id` | Evet | Kliniğe ait ürün. |
| `sessions[].products[].quantity` | Evet | Ürünün temel birimiyle miktar, 0,0001'den büyük. |
| `sessions[].products[].used` | Hayır | Varsayılan `true`. `false` satırlar kaydedilmez. |
| `sale_action` | Hayır | `none` (varsayılan), `create`, `append`. |

Listelenen seansın ürünleri `used: true` satırlarla değiştirilir; listelemediğiniz seanslar ürünlerini korur. `PUT` ile `status=completed` göndermek de çalışır ama ürün kaydetmez. Tamamlanmış randevuda tekrar çağırırsanız ürünler yeniden kaydedilir.

`sale_action` davranışı:

| Değer | Etki | İzin |
| - | - | - |
| `create` | Bağlı tüm seansların tedavilerinden ve ürünlerinden taslak satış oluşturur. | `Create:Sale` ve `sales:write` |
| `append` | Eksik tedavileri ekler, yeni ürün satırlarını ekler, mevcut ürün satırlarının miktarını günceller. Mevcut tedavi satırlarına dokunmaz. | `Update:Sale` ve `sales:write` |

| Kod | HTTP | Ne zaman |
| - | - | - |
| `APPOINTMENT_SALE_EXISTS` | 409 | `create` istediniz ama randevunun satışı var. `data.sale_id` mevcut satışı verir. |
| `APPOINTMENT_SALE_MISSING` | 422 | `append` istediniz ama randevunun satışı yok. |

```bash curl theme={null}
curl -X POST https://app.flextell.ai/api/v1/appointments/123/complete \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{
    "sessions": [
      {"session_id": 901, "products": [{"product_id": 55, "quantity": 2, "used": true}]}
    ],
    "sale_action": "create"
  }'
```

### Satış kalemleri

`GET /appointments/{id}/sale-items` satış oluşturma ekranını doldurmak için kalem listesi üretir; kayıt yazmaz. Token'ın hem `appointments:read` hem `sales:write` scope'u olmalı; kullanıcıda `View:Appointment` ve `Create:Sale` izni bulunmalıdır. Kalemler önce randevunun tedavileri (bağlı seanslardan gelenler dahil, tekrarsız), ardından bağlı seanslardaki ürünlerdir; ürünler ürün bazında toplanır. Henüz randevusu alınmamış seansların ürünleri dahil edilmez.

| Alan | Açıklama |
| - | - |
| `itemable_type`, `itemable_id` | `Treatment` veya `Product` ve kimliği. |
| `name`, `quantity` | Ad ve miktar (ürünlerde temel birim). |
| `unit_price`, `tax_rate`, `sub_total`, `total_tax`, `total_price` | `unit_price` KDV hariçtir. Katalog fiyatı KDV dahil kabul edilir: 120 fiyatlı, %20 vergili tedavi için `unit_price: 100`, `total_tax: 20`, `total_price: 120`. |
| `cost_price` | Maliyet fiyatı. |
| `staff_id` | Randevunun doktoru. |

Satışı oluşturmak için [Satışlar](/api/kaynaklar/satislar) sayfasına bakın.

## Silme ve seans randevuları

`DELETE /appointments/{id}` randevuyu yumuşak siler; başarıda `{"message": "Randevu başarıyla silindi"}` döner. Alt randevular ve hem randevunun hem alt randevuların satışları birlikte silinir; hepsi [Geri Dönüşüm Kutusu](/api/kaynaklar/loglar-ve-geri-donusum)'ndan birlikte geri yüklenir. Randevu hatırlatmaları kalıcı olarak silinir ve geri gelmez. Randevuya bağlı seanslar silinir, seans ürünleri yumuşak silinir; doktorun harici takvimindeki etkinlik kaldırılır.

Silmeden önce `GET /appointments/{id}/deletion-relations` ile etkilenecek kayıtları görün. Yanıt `{relation, label, count, deleted}` satırlarından oluşur; `relation` değeri `child_appointments` veya `sales` olur. Boş dizi, başka kayıt silinmeyeceği anlamına gelir.

Randevunun alt randevusu varsa (silinmiş olanlar dahil) `delete_child_appointments: true` göndermelisiniz; aksi hâlde `422` döner ve hata `id` alanına yazılır. Bu alan yalnızca onay bayrağıdır; silme her durumda alt randevulara da uygulanır. Alt randevuları tek tek de silebilirsiniz.

```bash curl theme={null}
curl -X DELETE https://app.flextell.ai/api/v1/appointments/123 \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{"delete_child_appointments": true}'
```

Genel silme kuralları için [Silme yaşam döngüsü](/api/istekler/silme-yasam-dongusu) sayfasına bakın.

## Genel hatalar

| Kod | HTTP | Ne zaman |
| - | - | - |
| `RESOURCE_NOT_FOUND` | 404 | Randevu yok veya size görünmüyor. |
| `FORBIDDEN` | 403 | Scope veya izin eksik. |
| `LEAD_NOT_ASSIGNED` | 403 | Yazma işlemi, size atanmamış bir lead'in hastasına dokunuyor. |
| `CUSTOMER_ERASED` | 409 | Hastanın verileri imha edilmiş; kayıt salt okunur. |
| `VALIDATION_FAILED` | 422 | Doğrulama hatası; ayrıntılar `errors` içindedir. |

Diğer ortak kodlar için [Hata kodları](/api/istekler/hata-kodlari) sayfasına bakın.


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