Entegrasyon
Ssemora'yı REST API ile sistemlerinize bağlayın.
HBYS gibi dış sistemler bir muayenenin ses kaydını Ssemora'ya gönderebilir, işleme durumunu izleyebilir ve hekim onaylı raporu JSON ya da Word olarak alabilir.
Dört Adımda Entegrasyon
-
Anahtar Alın
Kurumunuz için kapsamları ve sınırları belirlenmiş bir API anahtarı oluşturulur. Bağlantıyı
GET /integration/meile deneyin. -
Muayeneyi Gönderin
Ses dosyasını ve rıza beyanını
POST /integration/encountersile gönderin. Yanıt 202 ile gelir. -
Durumu İzleyin
Muayeneyi sorgulayın.
poll_after_secdoluyken işleme sürüyor demektir; bu değeri (3 sn) bekleme aralığı olarak kullanın. -
Raporu Alın
Hekim onayladığında rapor JSON ya da Word olarak alınır. Onaylanmamış rapor için 409
report_not_approveddöner.
Uç Noktalar
Tüm yollar /api/v1 önekiyle başlar; aşağıda önek yazılmamıştır. Kapsam sütunu, anahtarda bulunması gereken yetkiyi gösterir.
| Yöntem | Yol | Kapsam | Ne Yapar |
|---|---|---|---|
| GET | /integration/me | — | Anahtarı ve kurumu tanıtır; bağlantıyı denemek için kullanılır. |
| POST | /integration/encounters | encounters:write | Ses dosyası ve rıza ile muayene oluşturur (202). |
| GET | /integration/encounters | encounters:read | Muayeneleri listeler; external_ref ve page ile süzülür. |
| GET | /integration/encounters/{id} | encounters:read | Muayenenin işleme durumunu verir. |
| GET | /integration/encounters/{id}/report | reports:read | Raporu JSON olarak verir; kanıt aralıkları dahildir. |
| GET | /integration/encounters/{id}/report.docx | reports:read | Raporu Word dosyası olarak verir. |
| DELETE | /integration/encounters/{id} | encounters:write | Muayeneyi siler. Onaylı muayene silinemez (409 invalid_state). |
Muayene Oluştururken Gönderilen Alanlar
| Alan | Zorunlu | Açıklama |
|---|---|---|
audio | Evet | Ses dosyası: webm, wav, mp3, m4a, mp4, ogg, opus, flac ya da aac. |
consent_confirmed | Evet | Hasta rızasının alındığına dair beyan; true olmalıdır. Beyan, denetim günlüğüne source=api ile yazılır. |
external_ref | Hayır | Kendi sisteminizdeki kayıt numarası (en çok 200 karakter, benzersiz). Aynı değerle ikinci muayene 409 duplicate_external_ref döndürür. |
file_no, patient_ref, patient_name, subject_title | En az biri | Muayeneyi tanımlayan alanlar. Yanıtlarda hasta referansı maskelenir. |
template_id | Hayır | Kullanılacak rapor şablonunun kimliği. Bulunamazsa 422 template_not_found. |
subject_type | Hayır | Muayenenin konu türü. |
physician_username | Hayır | Muayenenin atanacağı hekimin kullanıcı adı. Bulunamazsa 422 physician_not_found. |
Örnekler
Örneklerde $SEMORA_URL kurumunuzun adresini, $SEMORA_API_KEY anahtarınızı gösterir. Anahtarı adres satırına yazmayın; yalnızca Authorization başlığında gönderin.
curl -X POST "$SEMORA_URL/api/v1/integration/encounters" \
-H "Authorization: Bearer $SEMORA_API_KEY" \
-F "audio=@muayene.webm" \
-F "consent_confirmed=true" \
-F "external_ref=HBYS-2026-0001" \
-F "file_no=A-1042"
{
"id": "6f1c2d3e-4a5b-6789-abcd-0123456789ab",
"external_ref": "HBYS-2026-0001",
"source": "api",
"status": "processing",
"progress_percent": null,
"error_code": null,
"subject_title": null,
"file_no": "A-1042",
"patient_ref_masked": null,
"created_at": "2026-10-27T09:15:03.120000Z",
"ended_at": "2026-10-27T09:15:03.101000Z",
"poll_after_sec": 3,
"links": {
"self": "/api/v1/integration/encounters/6f1c2d3e-4a5b-6789-abcd-0123456789ab",
"report": "/api/v1/integration/encounters/6f1c2d3e-4a5b-6789-abcd-0123456789ab/report",
"report_docx": "/api/v1/integration/encounters/6f1c2d3e-4a5b-6789-abcd-0123456789ab/report.docx"
}
}
import os
import time
import requests
BASE = os.environ["SEMORA_URL"]
HEADERS = {"Authorization": "Bearer " + os.environ["SEMORA_API_KEY"]}
with open("muayene.webm", "rb") as audio:
r = requests.post(
f"{BASE}/api/v1/integration/encounters",
headers=HEADERS,
data={"consent_confirmed": "true", "external_ref": "HBYS-2026-0001", "file_no": "A-1042"},
files={"audio": audio},
)
r.raise_for_status()
encounter = r.json()
# poll_after_sec dolu olduğu sürece muayene işleniyor.
while encounter["poll_after_sec"]:
time.sleep(encounter["poll_after_sec"])
encounter = requests.get(BASE + encounter["links"]["self"], headers=HEADERS).json()
# Hekim onaylayana kadar bu uç 409 report_not_approved döndürür.
report = requests.get(BASE + encounter["links"]["report"], headers=HEADERS)
print(report.status_code)
# JSON
curl "$SEMORA_URL/api/v1/integration/encounters/$ENCOUNTER_ID/report" \
-H "Authorization: Bearer $SEMORA_API_KEY"
# Word
curl "$SEMORA_URL/api/v1/integration/encounters/$ENCOUNTER_ID/report.docx" \
-H "Authorization: Bearer $SEMORA_API_KEY" \
-o rapor.docx
# Hekim onaylamadan taslağı görmek için
curl "$SEMORA_URL/api/v1/integration/encounters/$ENCOUNTER_ID/report?status=any" \
-H "Authorization: Bearer $SEMORA_API_KEY"
{
"encounter_id": "6f1c2d3e-4a5b-6789-abcd-0123456789ab",
"external_ref": "HBYS-2026-0001",
"encounter_status": "approved",
"report_status": "onaylandi",
"approved": true,
"report": {
"version": 1,
"status": "onaylandi",
"fields": {
"anamnez": {
"label": "Anamnez",
"content": "Üç gündür süren öksürük…",
"spans": [
{ "start": 120, "end": 168, "verified": true, "t_start": 12.4, "t_end": 19.0 }
],
"attention": [],
"edited": false
}
}
},
"text": "Anamnez\nÜç gündür süren öksürük…"
}
Her spans öğesi, cümlenin transkriptteki karakter aralığını (start, end) ve ses kaydındaki saniye aralığını (t_start, t_end) verir. attention alanı o bölümdeki dikkat öğelerini, edited hekimin düzenleyip düzenlemediğini gösterir.
Kimlik Doğrulama, Kapsamlar ve Sınırlar
Kimlik Doğrulama
Her istekte Authorization: Bearer smk_… başlığı gönderilir. Anahtarlar kurumunuz için Ssemora yönetimi tarafından oluşturulur; ad, kapsamlar, dakikalık sınır, azami dosya boyutu, isteğe bağlı son kullanma ve izinli IP/CIDR listesi oluşturulurken belirlenir. Anahtar yalnızca bir kez gösterilir.
Kapsamlar
encounters:write— muayene oluşturma (ses yükleme) ve silme.encounters:read— muayene durumunu ve listesini okuma.reports:read— raporu JSON ve Word olarak okuma.
Sınırlar
| Sınır | Değer | Aşılırsa |
|---|---|---|
| İstek hızı | Varsayılan: anahtar başına dakikada 60 (6000'e kadar ayarlanabilir) | 429 rate_limited ve Retry-After başlığı |
| Dosya boyutu | Varsayılan 25 MB (1–100 MB arası ayarlanabilir) | 413 payload_too_large |
| Ses biçimi | webm, wav, mp3, m4a, mp4, ogg, opus, flac, aac | 422 unsupported_audio_type |
| İzinli IP/CIDR | İsteğe bağlı liste | 403 ip_not_allowed |
| Son kullanma | İsteğe bağlı tarih | 401 api_key_expired |
Hata Sözleşmesi
Hatalar her zaman aynı JSON biçimindedir: ayrıntılı error nesnesi ile kısa code ve status alanları.
{
"error": {
"code": "report_not_approved",
"message": "Rapor henüz hekim tarafından onaylanmadı.",
"details": {}
},
"code": "report_not_approved",
"status": 409
}
| Durum | Kod | Anlamı |
|---|---|---|
| 400 | consent_required | consent_confirmed=true gönderilmedi. |
| 401 | missing_api_key | Authorization: Bearer başlığı yok. |
| 401 | invalid_api_key | Anahtar bulunamadı ya da biçimi geçersiz. |
| 401 | api_key_revoked | Anahtar iptal edilmiş. |
| 401 | api_key_inactive | Anahtar pasifleştirilmiş. |
| 401 | api_key_expired | Anahtarın son kullanma tarihi geçmiş. |
| 403 | ip_not_allowed | İstek, anahtarın izinli IP/CIDR listesi dışından geldi. |
| 403 | insufficient_scope | Anahtarın bu uç için gereken kapsamı yok (details.required_scopes). |
| 403 | tenant_inactive | Kurum hesabı etkin değil. |
| 404 | not_found | Kaynak yok ya da bu anahtarın erişimi dışında. |
| 405 | method_not_allowed | Bu yol için yöntem desteklenmiyor (Allow başlığına bakın). |
| 409 | duplicate_external_ref | Bu external_ref ile muayene zaten var (details.encounter_id). |
| 409 | report_not_approved | Rapor henüz hekim tarafından onaylanmadı; taslak için status=any. |
| 409 | not_ready | Muayene hâlâ işleniyor. |
| 409 | processing_failed | Muayene işlenemedi (details.error_code). |
| 409 | invalid_state | Muayenenin durumu bu işleme izin vermiyor (ör. onaylı muayene silinemez). |
| 413 | payload_too_large | Dosya, anahtarın azami boyutunu aşıyor. |
| 422 | validation_error | Alanlar geçersiz ya da eksik. |
| 422 | unsupported_audio_type | Ses biçimi desteklenmiyor. |
| 422 | template_not_found | Şablon bulunamadı ya da etkin değil. |
| 422 | physician_not_found | physician_username bulunamadı ya da etkin değil. |
| 429 | rate_limited | Dakikalık istek sınırı aşıldı (Retry-After). |
HBYS ile Bağlantı
Türkiye'de her hastanenin HBYS'si farklıdır. Bu yüzden Ssemora'ya tek bir ortak HBYS bağlantısı gömülmez: her kurum için o kurumun sistemine özgü bir bağlayıcı (adaptör) yazılır ve kurum ayarlarından seçilir. Bağlayıcının kimlik bilgileri kurum ayarlarında tutulur, kodun içine gömülmez.
Bağlayıcı arayüzü hasta sorgulama ve rapor kaydetme işlemlerini tanımlar. Tasarım kuralları şunlardır: aynı isteğin iki kez gitmemesi, kısmi başarının normal sayılması ve bir HBYS'nin yavaşlamasının uygulamayı kilitlememesi.
Bugünkü durum. Hazır bir HBYS bağlayıcısı yayımlamıyoruz; yalnızca arayüzü ve sınamaları örnekleyen bir örnek bağlayıcı vardır. Hangi HBYS'nin hedefleneceği, erişim bilgileri ve test ortamı kurumla birlikte planlanır. Bağlayıcıyı beklemeden de entegrasyon mümkündür: HBYS'niz muayeneyi API ile gönderir ve onaylı raporu geri alır.
Hiçbir veri, hekim onayı olmadan HBYS'ye gönderilmez.
Güvenlik Mimarisi
API'nin güvenlik özellikleri, anahtar düzeyinden veri düzeyine.
Anahtar Güvenliği
- Anahtar yalnızca oluşturulurken bir kez gösterilir; Ssemora yalnızca SHA-256 özetini saklar.
- Kapsam, isteğe bağlı son kullanma ve izinli IP/CIDR listesi anahtar başına tanımlanır.
- Dakikalık istek sınırı anahtar başınadır.
Erişim Sınırı
- Anahtar yalnızca kendi API ile oluşturduğu muayenelere dokunabilir.
- Rapor uçları varsayılan olarak yalnızca hekim onaylı raporu verir.
- Yanıtlarda hasta referansı maskelenir.
İzlenebilirlik
- Rıza beyanı zorunludur ve denetim günlüğüne
source=apiile yazılır. - API çağrı günlüğü 30 gün tutulur; istek gövdesi ve hasta verisi içermez.
Kurum İzolasyonu
- Her kurum kendi izole örneğinde ve veritabanında çalışır; kurumlar arasında veri paylaşılmaz.
- Anahtar tek bir kuruma bağlıdır; başka bir kurumun verisine erişemez.
Veri İşleme
Bir muayenenin verisi hangi adımda nerede işlenir?
| Adım | Nerede | Ayrıntı |
|---|---|---|
| Ses kaydı | Kurumun izole örneğinde | Varsayılan olarak 7 gün sonra silinir (kurum ayarıyla en çok 30 gün). Transkript ve rapor kalır. |
| Ses tanıma | Varsayılan olarak yerel (faster-whisper) | Ham ses yapay zekâ sağlayıcısına gönderilmez. Bulut ses tanıma yalnızca "bulut serbest" politikasında ve açık onayla kullanılabilir. |
| Kimliksizleştirme | Her zaman, politikadan bağımsız | Ad, T.C. kimlik no, dosya no, telefon, e-posta, adres, kurum adı ve kesin tarihler yer tutucuya çevrilir. Yaş, cinsiyet, klinik içerik ve "3 gündür" gibi göreli süreler korunur. Eşleme tablosu yalnızca tek istek boyunca bellekte tutulur; diske, günlüğe ya da önbelleğe yazılmaz. |
| Rapor ve öneri üretimi | Kurumun yapay zekâ politikasına göre | Bulut serbest ve yalnızca kimliksizleştirilmiş veri politikalarında kimliksiz metin bulut yapay zekâ sağlayıcılarına gönderilebilir. Yalnızca yerel model politikasında tüm aşamalar yerel modelde çalışır. |
| Sonuç | Kurumun izole örneğinde | Rapor, transkript ve kanıt aralıkları saklanır; onay, silme ve ayar değişiklikleri denetim günlüğüne yazılır. |
Artık risk. Doğrudan tanımlayıcılar kaldırılsa da çok küçük hasta popülasyonlarında (nadir hastalık, az hasta gören birim) dolaylı tanımlanabilirlik riski teorik olarak sıfırlanamaz. Bu nedenle yapay zekâ politikası kurum düzeyinde seçilir; yalnızca yerel model politikasında metin kurum dışına çıkmaz. Bu sayfa teknik bir özettir; sözleşme ve aydınlatma metinlerinin yerine geçmez.
Entegrasyonu Birlikte Planlayalım
Sisteminizi, hedeflediğiniz akışı ve sınırlarınızı anlatın; en uygun yolu birlikte belirleyelim.