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

# Hasta birleştirme

> Mükerrer hasta adaylarını bulmayı, birleştirme önizlemesini, birleştirmeyi ve hariç tutmaları anlatır.

Aynı kişinin iki kez açılmış hasta kayıtlarını bulur, karşılaştırır ve tek kayıtta birleştirirsiniz. Birleştirmede **kalacak hasta** (hedef) yol parametresindeki `{id}` hastasıdır. **Silinecek hasta** (kaynak) isteğin gövdesindeki `source_customer_id` hastasıdır. Kaynağın randevu, satış, dosya ve sohbet gibi ilişkili kayıtları hedefe taşınır.

Panelde aynı akış **Hasta Birleştirme** sayfasında bulunur. Panel anlatımı için [Hasta birleştirme (panel)](/panel/hastalar/birlestirme) sayfasına bakın.

<Warning>
  Birleştirme geri alınamaz. Kaynak hasta kalıcı olarak silinir ve Geri Dönüşüm Kutusu'ndan geri getirilemez. Birleştirmeden önce mutlaka [önizleme](#önizleme) isteği yapın.
</Warning>

## Endpoint özeti

Tüm endpoint'ler `/api/v1` altındadır ve `Authorization: Bearer <access_token>` ile `X-Tenant: <tenant_id>` başlıklarını ister. Hepsi için `Birleştir` izni (`Merge:Customer`) gerekir.

| Metot | Endpoint | Açıklama | Scope |
| - | - | - | - |
| GET | `/customers/duplicates` | Olası mükerrer hasta gruplarını listeler. | `customers:read` |
| GET | `/customers/{id}/duplicate-candidates` | Bir hastanın olası mükerrerlerini listeler. | `customers:read` |
| GET | `/customers/{id}/merge/preview` | Birleştirmenin sonucunu hiçbir şey yazmadan gösterir. | `customers:read` |
| POST | `/customers/{id}/merge` | `{id}` hastasına başka bir hastayı birleştirir. | `customers:write` |
| POST | `/customers/{id}/merge/exclusions` | İki hastayı "mükerrer değil" olarak işaretler. | `customers:write` |
| GET | `/customer-merges` | Tamamlanmış birleştirmelerin geçmişini listeler. | `customers:read` |
| GET | `/customer-merges/{id}` | Tek bir birleştirme kaydını, silinen hastanın anlık görüntüsüyle getirir. | `customers:read` |

Scope ve izin kuralları için [Scope'lar](/api/kimlik-dogrulama/scopelar) ve [İzinler ve görünürlük](/api/izinler-ve-gorunurluk) sayfalarına bakın.

## Mükerrer adaylar

Flextell iki hastayı yalnızca **ad ve soyadı aynıysa** mükerrer sayar. Karşılaştırma büyük/küçük harf ve baştaki/sondaki boşlukları yok sayar, Türkçe `İ`, `I` ve `ı` harflerini `i` olarak eşler. TC kimlik numarası ve telefon karşılaştırılmaz. Yalnızca kimlik numarası aynı olan iki hasta aday olarak önerilmez.

Yalnızca çağıran kullanıcının görebildiği hastalar hem adaylarda hem birleştirmede yer alır. Kapsamınızın dışındaki bir hasta için `404` alırsınız.

### Grup listesi

`GET /customers/duplicates` isteği `per_page` ve `page` parametrelerini alır. Gruplar üye sayısına göre azalan, sonra ada göre sıralanır.

| Alan | Tür | Açıklama |
| - | - | - |
| `display_name` | metin | Grubun görünen adı. |
| `member_count` | sayı | Gruptaki hasta sayısı. |
| `member_ids` | sayı dizisi | Üye hasta ID'leri. |
| `target_customer_id` | sayı | Önerilen kalacak hasta: en düşük ID. |
| `source_customer_id` | sayı | Önerilen silinecek hasta: sonraki en düşük ID. |
| `members` | nesne dizisi | Üyelerin kısa hasta kayıtları. |

<Note>
  `meta.total`, hariç tutulan çiftler ayıklanmadan önceki ad gruplarını sayar. Bu yüzden bir sayfada `per_page` değerinden az grup gelebilir. Sayfalama kuralları için [Sayfalama](/api/istekler/sayfalama) sayfasına bakın.
</Note>

### Tek hastanın adayları

`GET /customers/{id}/duplicate-candidates` isteği `limit` parametresini alır (1–100, varsayılan 10). Yanıtta `target` (istediğiniz hasta) ve `candidates` (adaylar, ID sırasıyla) döner. Hariç tutulan çiftler listeye girmez. Adı veya soyadı boş olan bir hastanın adayı çıkmaz.

```json theme={null}
{
  "success": true,
  "data": {
    "target": { "id": 123, "first_name": "Ayşe", "last_name": "Yılmaz", "phone_number": "+90 5xx xxx xx xx" },
    "candidates": [
      { "id": 456, "first_name": "Ayşe", "last_name": "Yılmaz", "phone_number": "+90 5xx xxx xx xx" }
    ]
  }
}
```

Bu örnekte yalnızca ilgili alanlar gösterilmiştir. Aday nesnelerinde ayrıca `id`, `record_state`, `email`, `is_masked`, `is_lead_stage` ve `lead_id` alanları bulunur.

<Info>
  Verileri imha edilmiş hastalar da gruplarda ve adaylarda görünür, ancak birleştirilemez (bkz. [Kısıtlar](#kısıtlar)).
</Info>

## Önizleme

`GET /customers/{id}/merge/preview?source_customer_id=456` isteği iki kaydı alan alan karşılaştırır ve birleştirme sonucunda taşınacak kayıtları sayar. Hiçbir şey yazmaz.

<ParamField query="source_customer_id" type="integer" required>
  Silinecek hastanın ID'si. `{id}` ile aynı olamaz.
</ParamField>

Yanıt üç parçadan oluşur.

| Alan | Açıklama |
| - | - |
| `fields` | Birleştirilebilir alanların listesi. Her öğe `key`, `label`, `target`, `source` ve `differs` içerir. `differs`, iki değer farklıysa `true` olur. |
| `counts` | Taşınacak kayıt sayıları; anahtar tablo adıdır (örn. `appointments`, `sales`). |
| `total` | `counts` içindeki tüm sayıların toplamı. |

`target` ve `source` değerleri ham gelir. Ülke, il, ilçe, meslek, kanal ve sorumlu kullanıcı için ID, `gender` için sabit değer, doğum tarihi için `Y-m-d` biçimi, `avatar_url` için dosya anahtarı döner. İnsan tarafından okunacak ad için ilgili hasta kayıtlarını ayrıca okuyun.

`counts` ve `total`, aktivite kaydı, birleştirme geçmişi ve hariç tutma kayıtları gibi iç kayıtları da sayar. Panel bu kalemleri gizler. Kullanıcıya gösterecekseniz `activity_log`, `customer_merges` ve `customer_merge_exclusions` anahtarlarını ayıklayabilirsiniz.

### Birleştirilebilir alanlar

Her alan için `target` (kalacak hastanın değeri) ya da `source` (silinecek hastanın değeri) seçebilirsiniz.

| `key` | `label` |
| - | - |
| `first_name` | Ad |
| `last_name` | Soyad |
| `phone_number` | Telefon |
| `email` | E-posta |
| `date_of_birth` | Doğum Tarihi |
| `gender` | Cinsiyet |
| `identity_number` | TC Kimlik No |
| `passport_number` | Pasaport No |
| `country_id` | Ülke |
| `city_id` | İl |
| `district_id` | İlçe |
| `occupation_id` | Meslek |
| `address` | Adres |
| `default_channel_id` | Varsayılan Kanal |
| `user_id` | Sorumlu Kullanıcı |
| `avatar_url` | Profil Fotoğrafı |

## Birleştirme

`POST /customers/{id}/merge` isteği birleştirmeyi yapar.

<ParamField body="source_customer_id" type="integer" required>
  Silinecek hastanın ID'si. `{id}` ile aynı olamaz.
</ParamField>

<ParamField body="field_selections" type="object">
  Alan adı → `target` veya `source` eşlemesi. Anahtarlar yukarıdaki 16 alandan biri olmalıdır. Göndermediğiniz alanlarda `target` değeri kalır.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://app.flextell.ai/api/v1/customers/123/merge" \
    -H "Authorization: Bearer <access_token>" \
    -H "X-Tenant: <tenant_id>" \
    -H "Content-Type: application/json" \
    -d '{
      "source_customer_id": 456,
      "field_selections": { "phone_number": "source", "email": "target" }
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://app.flextell.ai/api/v1/customers/123/merge", {
    method: "POST",
    headers: {
      Authorization: "Bearer <access_token>",
      "X-Tenant": "<tenant_id>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      source_customer_id: 456,
      field_selections: { phone_number: "source", email: "target" },
    }),
  });
  ```
</CodeGroup>

```json theme={null}
{
  "success": true,
  "data": {
    "customer": { "id": 123, "first_name": "Ayşe", "last_name": "Yılmaz" },
    "merge": {
      "id": 7,
      "source_customer_id": 456,
      "source_customer_name": "Ayşe Yılmaz",
      "moved_counts": { "appointments": 3, "sales": 1 },
      "total_moved_count": 4
    }
  }
}
```

Yanıttaki `customer` kaydında `notification_channels` ve `import_source` alanları yoktur, `latest_conversation_id` ise `null` döner. Güncel hâli için hastayı `GET /customers/{id}` ile yeniden okuyun.

### Neler olur

* Kaynağın şu kayıtları hedefe taşınır: randevular, satışlar, destek talepleri, mesajlar, sohbetler, hasta işlemleri, formlar, faturalar, teklifler, AI yanıt önerileri, lead'ler, görevler, veri imha talepleri, notlar, dosyalar, etiketler, iletişim kimlikleri ve kara liste kayıtları. Silinmiş (geri dönüşüm kutusundaki) kayıtlar da taşınır.
* Hedefte zaten bulunan etiketler tekrar eklenmez. Aynı kanalda hedefin zaten birincil kimliği varsa kaynağın birincil kimliği birincillikten çıkar.
* Hedefin lead'i yoksa ve kaynağın varsa, hedef kaynağın lead'ini devralır ve hasta olarak kalır. Hedefte kayıtlı bir içe aktarma kaynağı yoksa kaynaktakini alır.
* Kaynaktaki telefon numarası aynı işlemde serbest kalır; bu sayede `phone_number` için `source` seçebilirsiniz.
* Korunmayan dolu alan değerleri (hedefin ezilen değeri ya da silinen kaydın değeri) hedef hastaya otomatik bir not olarak yazılır. Not, `Hasta birleştirme: "<kaynak adı>" kaydı birleştirilirken korunmayan dolu alanlar:` satırıyla başlar ve birleştiren kullanıcıya aittir.
* İşlem bir bütündür. Bir adım başarısız olursa hiçbir değişiklik kalmaz.
* Kaynağın dosyaları, birleştirme yanıtı döndükten sonra hedefin klasörüne taşınır. Dosyaların yeni konumda görünmesi kısa süre alabilir.

### Birleştirme geçmişi

Her birleştirme bir geçmiş kaydı bırakır. `GET /customer-merges` listesi şu parametreleri alır.

| Parametre | Açıklama |
| - | - |
| `search` | Silinen hastanın adında arama (büyük/küçük harf duyarsız). |
| `target_customer_id` | Kalan hastaya göre filtre. |
| `performed_by_user_id` | Birleştiren kullanıcıya göre filtre. |
| `created_at_from`, `created_at_to` | Tarih aralığı. |
| `sort_by` | `created_at`, `updated_at`, `source_customer_name`. |
| `sort_order` | Sıralama yönü. |
| `per_page`, `page` | Sayfalama. |

Liste kayıtları `id`, `target_customer_id`, `source_customer_id`, `source_customer_name`, `performed_by_user_id`, `field_selections`, `moved_counts`, `total_moved_count`, `target_customer`, `performed_by`, `created_at` ve `updated_at` alanlarını içerir. Detay endpoint'i ek olarak `source_snapshot` döndürür: silinen hasta kaydının tam kopyası.

<Warning>
  Geçmiş kayıtları hasta kapsamına göre süzülmez; `Birleştir` iznine sahip her kullanıcı klinikteki tüm birleştirmeleri ve `source_snapshot` içindeki kişisel verileri görür. Bu izni yalnızca gerekli kullanıcılara verin.
</Warning>

## Hariç tutma

İki kaydın gerçekten farklı kişiler olduğunu biliyorsanız `POST /customers/{id}/merge/exclusions` ile çifti "mükerrer değil" olarak işaretleyin.

<ParamField body="source_customer_id" type="integer" required>
  Diğer hastanın ID'si. `{id}` ile aynı olamaz.
</ParamField>

```bash theme={null}
curl -X POST "https://app.flextell.ai/api/v1/customers/123/merge/exclusions" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{ "source_customer_id": 456 }'
```

| Durum | HTTP | `data.created` |
| - | - | - |
| Çift ilk kez işaretlendi. | `201` | `true` |
| Çift daha önce işaretlenmişti. | `200` | `false` |

Yanıttaki `target_customer_id` her zaman düşük ID'yi, `source_customer_id` yüksek ID'yi gösterir; hangi tarafı gönderdiğiniz fark etmez. `data.message` çevrilmeyen İngilizce bir metindir; mantığınızı `created` alanına bağlayın.

* İşaretlenen çift tüm grup ve aday listelerinden çıkar. Bir grupta kalan üyeler artık mükerrer çift oluşturmuyorsa grup kaybolur.
* İşaret **sonradan kaldırılamaz**; bunun için bir endpoint yoktur.
* Verileri imha edilmiş hastalar için de işaret koyabilirsiniz.

## Kısıtlar

| Kod | HTTP | Ne zaman |
| - | - | - |
| `VALIDATION_FAILED` | 422 | `source_customer_id` eksik ya da `{id}` ile aynı (önizleme, birleştirme, hariç tutma); `field_selections` bilinmeyen bir alan, `target`/`source` dışında bir değer içeriyor ya da nesne değil. |
| `MERGE_CUSTOMER_ERASED` | 422 | Önizlemede ya da birleştirmede iki taraftan birinin açık bir Veri İmha Talebi var. Önizlemede imha edilmiş bir hasta da bu kodu verir. |
| `CUSTOMER_ERASED` | 409 | Birleştirmede taraflardan biri zaten imha edilmiş. |
| `FORBIDDEN` | 403 | Scope ya da `Birleştir` izni eksik. |
| `RESOURCE_NOT_FOUND` | 404 | Hasta ya da kaynak hasta bulunamadı, silinmiş, başka klinikte ya da görünürlük kapsamınızın dışında. Geçmiş kaydı yoksa `Hasta birleştirme kaydı bulunamadı`. |

Başka kurallar:

* Lead aşamasındaki kayıtlar hasta sayılmaz. Bunlar için bu endpoint'ler `404` verir; kayıt, lead hastaya dönüştükten sonra görünür.
* Başka bir kliniğin hastası ya da silinmiş (Geri Dönüşüm Kutusu'ndaki) hasta birleştirilemez.
* Birleştirme geri alınamaz ve hariç tutma işareti kaldırılamaz.
* Her iki hasta da hasta kapsamınızda olmalıdır; kapsam kuralları için [İzinler ve görünürlük](/api/izinler-ve-gorunurluk) sayfasına bakın.

Genel hata biçimi ve kodlar için [Hata kodları](/api/istekler/hata-kodlari) sayfasına bakın.

<CardGroup cols={2}>
  <Card title="Hastalar" icon="users" href="/api/kaynaklar/hastalar">
    Hasta kayıtlarını listeleme, oluşturma ve düzenleme.
  </Card>

  <Card title="Veri imha talepleri" icon="shield" href="/api/kaynaklar/veri-imha-talepleri">
    Birleştirmeyi engelleyen açık imha talepleri.
  </Card>
</CardGroup>


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