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

# Hastalar

> Hasta kaydı oluşturmayı, listelemeyi, güncellemeyi, iletişim kimliklerini, etiketleri ve görünürlük kurallarını anlatır.

Hasta, kliniğin (`X-Tenant`) kayıtlı kişisidir. Randevular, satışlar, notlar, görevler, formlar ve sohbetler hastaya bağlanır. Bu sayfa hastanın kendisini yönetir: kayıt, arama, güncelleme, iletişim kimlikleri, etiketler, silme ve görünürlük. Notlar, birleştirme ve formlar kendi sayfalarındadır: [Hasta notları ve görevleri](/api/kaynaklar/hasta-notlari-ve-gorevleri), [Hasta birleştirme](/api/kaynaklar/hasta-birlestirme), [Hasta formları](/api/kaynaklar/hasta-formlari).

<Info>
  Her istekte `Authorization: Bearer <access_token>` ve `X-Tenant: <tenant_id>` başlıkları gerekir. Başlık yoksa `400 TENANT_HEADER_REQUIRED` döner. Ayrıntı: [Klinikler ve X-Tenant](/api/klinikler-ve-x-tenant).
</Info>

## Endpoint özeti

Taban adres `https://app.flextell.ai/api/v1`. Okuma uç noktaları `customers:read`, yazma uç noktaları `customers:write` scope'u ister. Scope'lar hakkında: [Scope'lar](/api/kimlik-dogrulama/scopelar).

| Metot | Endpoint | Açıklama | İzin |
| - | - | - | - |
| GET | `/customers` | Hastaları listeler | `View:Customer` |
| POST | `/customers` | Hasta oluşturur | `Create:Customer` |
| GET | `/customers/{id}` | Tek hasta döner | `View:Customer` |
| PUT | `/customers/{id}` | Hastayı kısmen günceller | `Update:Customer` |
| DELETE | `/customers/{id}` | Hastayı siler | `Delete:Customer` |
| GET | `/customers/{id}/files` | Hastanın dosyalarını `group_id` ile gruplayarak döner | `View:Customer` ve `View:File` |
| GET | `/customers/{id}/identities` | İletişim kimliklerini listeler | `View:Customer` ve `View:CustomerIdentity` |
| POST | `/customers/{id}/identities` | İletişim kimliği ekler | `View:Customer` ve `Create:CustomerIdentity` |
| GET | `/customers/{id}/identities/{identityId}` | Tek kimlik döner | `View:Customer` ve `View:CustomerIdentity` |
| PUT | `/customers/{id}/identities/{identityId}` | Kimliği günceller | `View:Customer` ve `Update:CustomerIdentity` |
| DELETE | `/customers/{id}/identities/{identityId}` | Kimliği siler | `View:Customer` ve `Delete:CustomerIdentity` |

Kimlik uç noktaları da aynı kuralı izler: okuma `customers:read`, yazma `customers:write`. `/customers/{id}/files` için dosya scope'u gerekmez, ama `View:File` izni gerekir.

Panelde bu izinler rol editöründe **Hastalar** grubunda (**Görüntüle**, **Tümünü Görüntüle**, **Oluştur**, **Güncelle**, **Birleştir**, **Sil**) ve **Hasta İletişim Kanalları** grubunda görünür.

## Nesne modeli

Tek hasta ve liste yanıtları aynı alanları taşır. Tarih-saat alanları klinik saat dilimiyle ofsetli döner (`2026-10-12T14:30:00+03:00`), `date_of_birth` ise `YYYY-MM-DD` biçimindedir.

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Hasta kimliği |
| `record_state` | object | `is_read_only` ve `reason_code` (`CUSTOMER_ERASED` veya `null`). Bkz. "İmha edilmiş hasta" bölümü |
| `first_name`, `last_name` | string | Ad, soyad |
| `phone_number` | string | Yalnızca rakamlar, `+` olmadan (`905xxxxxxxxx`) |
| `email` | string veya null | E-posta |
| `date_of_birth` | date veya null | Doğum tarihi |
| `gender` | string veya null | `male`, `female` veya `other` |
| `country_id`, `country_name`, `city_id`, `city_name`, `district_id`, `district_name` | integer / string | Ülke, şehir, ilçe |
| `identity_number` | string veya null | TCKN, 11 hane |
| `passport_number` | string veya null | Pasaport numarası |
| `occupation_id`, `occupation_name` | integer / string | Meslek. Adlar büyük harfle saklanır |
| `address` | string veya null | Adres |
| `default_channel_id`, `default_channel_name` | integer / string | Varsayılan kanal |
| `latest_conversation_id` | integer veya null | Yalnızca token'da `conversations:read` scope'u ve kullanıcıda `View:Conversation` izni varsa dolu gelir |
| `avatar_url` | string veya null | Profil fotoğrafının imzalı URL'si. Fotoğraf haftalık olarak WhatsApp'tan güncellenir; URL yaklaşık 6 saat geçerlidir |
| `is_lead_stage`, `lead_id` | boolean / integer | Hastaya bağlı Lead bilgisi |
| `is_masked` | boolean | Bu uç noktalarda `false` döner |
| `related_user` | object veya null | **İlgili Personel**: `id`, `name` |
| `tags` | array | Etiket nesneleri (`id`, `name`, `color`) |
| `notification_channels` | object | Yalnızca `GET` ve `PUT` `/customers/{id}` yanıtlarında |
| `import_source` | object veya null | İçe aktarıldığı sistem. Yalnızca tek hasta yanıtlarında (`GET`, `POST`, `PUT` `/customers`); listede yoktur |
| `created_at`, `updated_at`, `deleted_at`, `erased_at` | datetime | Zaman damgaları |

<Note>
  `user_id` yalnızca yazarken kullanılır, okurken `related_user` döner. Aşağıdaki alanlar API'den yazılamaz: `lead_id`, `converted_at`, `import_source_id`, `avatar_url`, `is_intake_completed`, `erased_at`.
</Note>

## Listeleme ve filtreler

`GET /customers` lead aşamasındaki ve silinmiş kayıtları döndürmez. İmha edilmiş hastalar varsayılan olarak listelenir. Sayfalama (`per_page` 1–100, varsayılan 15; `page`) ve yanıt zarfı için [Sayfalama](/api/istekler/sayfalama) ile [Yanıt yapısı](/api/istekler/yanit-yapisi) sayfalarına bakın.

| Parametre | Açıklama |
| - | - |
| `search` | En fazla 255 karakter. Ad, soyad, e-posta ve kimlik numarasında aksan ve büyük/küçük harf duyarsız alt dize araması yapar; boşlukla ayrılan her kelime eşleşmelidir. Telefon, terimdeki rakamlarla eşleşir (`0532 123` terimi `905321234567` ile eşleşir). Pasaport numarasında aranmaz. En az 2 karakterlik bir kelime ya da en az 3 rakamlık bir telefon parçası yoksa sonuç dönmez |
| `gender` | `male`, `female`, `other` |
| `min_age`, `max_age` | Tam sayı, 0 veya üstü. Yaşı en az / en çok bu değer olan hastalar. Doğum tarihi olmayan hastalar iki filtrede de elenir. Bugün, sunucu saatine göre hesaplanır |
| `user_id` | **İlgili Personel** kullanıcısı. Lead'in atanan kullanıcısını filtrelemez |
| `occupation_id` | Meslek |
| `tags[]` | Etiket kimlikleri. Herhangi biriyle eşleşen hasta gelir |
| `has_email` | `1`, `0`, `true`, `false`. `0`, e-postası boş ve hiç girilmemiş kayıtları kapsar |
| `exclude_erased` | `1` ise imha edilmiş hastalar listeden çıkar. Yeni randevu veya satış seçicileri için uygundur |
| `created_at_from`, `created_at_to` | Oluşturulma aralığı. Günler klinik saat dilimine göre alınır |
| `date_of_birth_from`, `date_of_birth_to` | Doğum tarihi aralığı |
| `sort_by` | `first_name`, `last_name`, `date_of_birth`, `gender`, `created_at`, `updated_at`. Varsayılan `created_at`. Başka değer `422` döner |
| `sort_order` | `asc` veya `desc` (küçük harf). Varsayılan `desc` |

Aralık parametrelerinde uç değerler dahildir; yalnızca tarih içeren `_to` değeri günün tamamını kapsar ve `_from` değerinden önce olamaz. Sıralama genel kuralları için [Filtreleme ve sıralama](/api/istekler/filtreleme-ve-siralama) sayfasına bakın. `sort_by` tek başına verilirse metin sütunları Türkçe sıralamayla A→Z, diğerleri azalan sıralanır.

```bash theme={null}
curl -G "https://app.flextell.ai/api/v1/customers" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  --data-urlencode "search=Ayşe" \
  --data-urlencode "tags[]=12" \
  --data-urlencode "exclude_erased=1" \
  --data-urlencode "sort_by=last_name" \
  --data-urlencode "per_page=25"
```

## Oluşturma ve güncelleme

`POST /customers` hasta oluşturur ve `201` döner. `PUT /customers/{id}` kısmi güncellemedir: gönderdiğiniz alanlar değişir. Zorunlu üç alan güncellemede atlanabilir ama boş gönderilemez.

| Alan | Zorunlu | Kural |
| - | - | - |
| `first_name`, `last_name` | Oluşturmada evet | En fazla 255 karakter |
| `phone_number` | Oluşturmada evet | Doğrulamadan önce normalleştirilir. En fazla 20 karakter. Klinikte, silinmemiş hastalar arasında tekil olmalıdır |
| `email` | Hayır | Geçerli e-posta, en fazla 255 karakter |
| `date_of_birth` | Hayır | Bugünden önce bir tarih |
| `gender` | Hayır | `male`, `female`, `other` |
| `country_id`, `city_id`, `district_id` | Hayır | Üst kimlik aynı istekte gönderilirse şehir ülkeye, ilçe şehre ait olmalıdır |
| `identity_number` | Hayır | Tam 11 rakam. Klinikte tekil; `11111111111` ve `00000000000` yer tutucuları tekrar edebilir |
| `passport_number` | Hayır | 6–12 karakter, yalnızca `A-Z` ve `0-9`. Sunucu büyük harfe çevirir. Klinikte tekil |
| `occupation_id` | Hayır | Aktif ve silinmemiş bir meslek; genel veya kliniğe ait olmalıdır. Bkz. [Meslekler ve etiketler](/api/kaynaklar/meslekler-ve-etiketler) |
| `address` | Hayır | En fazla 1000 karakter |
| `user_id` | Hayır | **İlgili Personel**. Kliniğin kullanıcısı olmalıdır. Varsayılan olarak çağıranla doldurulmaz |
| `default_channel_id` | Hayır | Klinikte aktif bir kanal. Aşağıdaki nota bakın |
| `tags` | Hayır | Kliniğe ait etiket kimlikleri dizisi |

Telefon normalleştirmesi: `@` sonrası ve rakam olmayan her karakter atılır. `5` ile başlayan 10 hane başına `90` alır; `0` ile başlayan 11 hane `0` yerine `90` alır. Diğer numaralar olduğu gibi kalır, bu yüzden uluslararası numaralarda ülke kodunu gönderin. `@lid` ile biten WhatsApp kimlikleri hiç değiştirilmez. `+90 5xx xxx xx xx`, `05xx xxx xx xx` ve `5xxxxxxxxx` aynı kayda çözülür. Silinen hastanın telefon, TCKN ve pasaport numarası hemen yeniden kullanılabilir.

<Warning>
  `tags` gönderdiğinizde etiket kümesinin tamamı değiştirilir. Boş dizi (`[]`) veya `null` tüm etiketleri kaldırır. Alanı hiç göndermezseniz etiketler değişmez. Başka kliniğe ait etiket kimliği `422` döner.
</Warning>

<Note>
  **Varsayılan kanal.** Oluşturmada yalnızca telefon tabanlı aktif bir kanal ve dolu `phone_number` kabul edilir. Güncellemede hastanın o kanalda sohbeti ya da kimliği olmalı; kanal telefon tabanlıysa kayıtlı telefon yeterlidir. Aksi halde `422` ve `Hastanın seçilen varsayılan kanalda kayıtlı adresi yok.` döner. Oluşturmadaki ret mesajı İngilizcedir ve çevrilmez.
</Note>

Kontrol sırası şöyledir: scope ve izin (`403`), alan doğrulaması (`422`), hasta bulunamadı veya görünürlük dışı (`404`), imha edilmiş hasta (`409`). Bu yüzden geçersiz gövdeyle olmayan bir kimliğe yazarsanız `404` değil `422` alırsınız.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://app.flextell.ai/api/v1/customers" \
    -H "Authorization: Bearer <access_token>" \
    -H "X-Tenant: <tenant_id>" \
    -H "Content-Type: application/json" \
    -d '{
      "first_name": "Ayşe",
      "last_name": "Yılmaz",
      "phone_number": "+90 5xx xxx xx xx",
      "email": "ayse@example.com",
      "gender": "female",
      "tags": [12, 14]
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://app.flextell.ai/api/v1/customers", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "X-Tenant": tenantId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      first_name: "Ayşe",
      last_name: "Yılmaz",
      phone_number: "+90 5xx xxx xx xx",
      tags: [12, 14],
    }),
  });
  const { data } = await res.json();
  ```
</CodeGroup>

```json theme={null}
{
  "success": true,
  "data": {
    "id": 123,
    "record_state": { "is_read_only": false, "reason_code": null },
    "first_name": "Ayşe",
    "last_name": "Yılmaz",
    "phone_number": "905xxxxxxxxx",
    "email": "ayse@example.com",
    "tags": [{ "id": 12, "name": "VIP", "color": "#6b7280" }],
    "import_source": null,
    "created_at": "2026-10-12T14:30:00+03:00"
  }
}
```

## İletişim kimlikleri

İletişim kimliği, hastanın bir kanaldaki adresidir: WhatsApp numarası, Telegram sohbet kimliği, Instagram kullanıcı kimliği (IGSID) veya web sitesi ziyaretçi kimliği. Panelde **İletişim Kanalları** sekmesinde görünür. Kanallar için [Kanallar](/api/kaynaklar/kanallar) sayfasına bakın.

| Alan | Zorunlu | Kural |
| - | - | - |
| `channel_id` | Oluşturmada evet | Klinikteki bir kanal |
| `identifier` | Oluşturmada evet | En fazla 255 karakter. API değeri olduğu gibi saklar, telefon normalleştirmesi yapmaz. Aynı kanalda, silinmemiş kimlikler arasında tekil olmalıdır |
| `is_primary` | Hayır | Bir hastanın bir kanalda en fazla bir birincil kimliği olur. `true` göndermek önceki birincili otomatik düşürür |
| `metadata` | Hayır | Serbest JSON nesnesi |

Liste `channel_id` ile filtrelenir, `created_at_from` ve `created_at_to` ile daraltılır; birincil kimlikler önce gelir. Her kimlik `id`, `record_state`, `channel` (`id`, `name`, `type`), `identifier`, `is_primary`, `metadata`, `created_at` ve `updated_at` alanlarıyla döner. Kimliği silmek adresi serbest bırakır. Yeni bir kimlik, hastanın `notification_channels` bilgisine yansır.

```bash theme={null}
curl -X POST "https://app.flextell.ai/api/v1/customers/123/identities" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{"channel_id": 7, "identifier": "905xxxxxxxxx", "is_primary": true}'
```

## Görünürlük

Hasta görünürlüğü kullanıcının iznine ve Lead atamasına bağlıdır. Görünürlük kurallarının dışında kalan hasta `403` değil, her zaman `404` döner; okuma ve yazmada aynıdır.

1. Lead aşamasındaki kayıtlar hasta sayılmaz. Lead hastaya dönüşene kadar bu uç noktalarda `404` döner. Bkz. [Lead'ler](/api/kaynaklar/leadler).
2. `ViewAllCustomers:Customer` (**Tümünü Görüntüle**) görünürlük anahtarıdır. Bu izne sahip kullanıcılar ve platform yöneticileri kliniğin tüm hastalarını görür. İzin açıkça verilmedikçe geçerli değildir.
3. İzin yoksa **Satış Temsilcisi** rolü, dönüştürülmüş ve Lead'siz tüm hastaları ve kendi Lead'lerinin kayıtlarını görür.
4. İzin yoksa diğer roller (doktor, asistan gibi) yalnızca Lead'i kendilerine atanmış hastaları görür. Doğrudan, Lead'siz oluşturulmuş hastalar ve atanmamış Lead'lerin hastaları onlara görünmez.
5. **İlgili Personel** (`user_id`) görünürlük sağlamaz.

Varsayılan roller: **Satış Temsilcisi** rolünde `View:Customer`, `Update:Customer` ve `Create:CustomerIdentity`, `Update:CustomerIdentity`, `Delete:CustomerIdentity` vardır; `ViewAllCustomers:Customer` yoktur. **Satış Direktörü** rolünde `ViewAllCustomers:Customer` dahil `View:Customer`, `Create:Customer`, `Update:Customer` ve `Delete:Customer` vardır. Ayrıntılar için [İzinler ve görünürlük](/api/izinler-ve-gorunurluk) sayfasına bakın.

## Silme ve imha edilmiş hasta

### Silme

`DELETE /customers/{id}` hastayı yumuşak siler ve `Hasta başarıyla silindi` mesajını döner. Aynı Geri Dönüşüm Kutusu grubunda şunlar da silinir: ileri tarihli bekleyen veya onaylı randevular, sohbetler, Destek Talepleri, hasta formları, iletişim kimlikleri, notlar, görevler ve dosyalar. Geçmiş randevular, satışlar, teklifler, faturalar ve hesap hareketleri kalır ve `customer_name` bilgisini korur. "İlişkili kayıt var" engeli yoktur.

Silinen hasta her yerde `404` döner. Hastayı geri getiren bir API uç noktası yoktur; kayıt, süre dolana kadar (varsayılan 30 gün) Geri Dönüşüm Kutusu'ndan geri yüklenir. Bkz. [Silme yaşam döngüsü](/api/istekler/silme-yasam-dongusu) ve [Loglar ve geri dönüşüm](/api/kaynaklar/loglar-ve-geri-donusum).

### İmha edilmiş hasta

Hasta KVKK kapsamında veri imhası istediğinde kayıt silinmez, salt okunur olur. Bkz. [Veri imha talepleri](/api/kaynaklar/veri-imha-talepleri).

* Hasta listelerde ve detayda görünmeye devam eder; `erased_at` dolu, `record_state` ise `{"is_read_only": true, "reason_code": "CUSTOMER_ERASED"}` olur. Hastaya bağlı kayıtlar da aynı durumu taşır.
* Kişisel alanlar maskelenmiş döner. Ad her kelimede ilk iki harfi, doğum tarihi yalnızca yılı korur; adres tamamen `••••••` olur.
* Hasta ve kayıtları üzerindeki her yazma (güncelleme, silme, kimlik, not, görev) hiçbir değişiklik yapılmadan `409 CUSTOMER_ERASED` döner.
* Yeni iş açan seçicilerde `exclude_erased=1` kullanın.

<Note>
  `record_state.is_read_only` değerinin `false` olması yazma izniniz olduğu anlamına gelmez; izin kontrolleri ayrıca uygulanır.
</Note>

## Hata kodları

Genel hata yapısı için [Hatalar](/api/istekler/hatalar) ve [Hata kodları](/api/istekler/hata-kodlari) sayfalarına bakın.

| Kod | HTTP | Ne zaman |
| - | - | - |
| `UNAUTHENTICATED` | 401 | Token yok veya geçersiz |
| `FORBIDDEN` | 403 | Scope eksik (`Invalid scope(s) provided.`) veya izin yok (`Bu işlem için yetkiniz yok.`) |
| `RESOURCE_NOT_FOUND` | 404 | `Hasta bulunamadı`, `Hasta kimliği bulunamadı`: kayıt yok, başka kliniğe ait, görünürlük dışı, Lead aşamasında veya silinmiş |
| `CUSTOMER_ERASED` | 409 | İmha edilmiş hasta üzerinde yazma: `Bu hastanın verileri imha edildi; kayıt salt okunurdur.` |
| `VALIDATION_FAILED` | 422 | `Gönderilen veriler geçersiz.` ve `errors` nesnesi: benzersizlik ihlali (`phone_number`, `identity_number`, `passport_number`, `identifier`), biçim hataları, bilinmeyen `sort_by`, sayısal olmayan `id` |
| `TENANT_HEADER_REQUIRED` | 400 | `X-Tenant` başlığı yok |
| `TENANT_NOT_FOUND` | 404 | Klinik bulunamadı |
| `MALFORMED_JSON` | 400 | İstek gövdesi geçersiz JSON |
| `SUBSCRIPTION_REQUIRED`, `ACCESS_RESTRICTED_BY_OVERDUE_PAYMENT` | 402 | Abonelik veya gecikmiş ödeme kilidi. Bkz. [Erişim kilitleri](/api/istekler/erisim-kilitleri) |
| `SETUP_REQUIRED` | 428 | Klinik kurulumu tamamlanmamış |
| `TOO_MANY_REQUESTS` | 429 | İstek sınırı aşıldı. Bkz. [Oran sınırları](/api/istekler/oran-sinirlari) |


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