Make Endorsement

## Make Endorsement Offline bir işe ait zeyil bilgilerini sigorta şirketi adına kaydeder. Servis isteği doğrular, token'daki sigorta şirketi ve iş sahipliği yetkisini kontrol eder, ardından `EndorsementMade` state machine geçişini tetikleyerek işi `Zeyil İsteği (EndorsementRequested)` aşamasından `Zeyil Gerçekleşti (EndorsementMade)` aşamasına taşır. Başarılı çağrı gövde döndürmez. ### Uç Nokta (Endpoint) `POST {{baseUrl}}/api/offline/jobs/:jobId/endorsements` `Content-Type: application/json` --- ### Kullanım Bu servis, platform tarafından açılmış bir zeyil isteğini sigorta şirketinin sonuçlandırması için kullanılır. Önerilen akış: 1. `POST /api/authentication/login` ile token alınır. 2. `GET /api/offline/jobs` ile `Zeyil İsteği` aşamasındaki işler listelenir ve işlenecek `jobId` belirlenir. 3. `GET /api/offline/jobs/:jobId/actions` ile zeyil isteğinin detayı (istenen değişiklik, ekler) okunur. 4. Zeyil sigorta şirketinin kendi sisteminde üretilir; poliçe, prim ve taksit bilgileri toplanır. 5. Bu servis çağrılır. `204 No Content` dönmesi zeyilin kaydedildiği ve işin `Zeyil Gerçekleşti` aşamasına geçtiği anlamına gelir. 6. Zeyil yapılamıyorsa bu servis yerine `POST /api/offline/jobs/:jobId/endorsements/reject` çağrılarak istek reddedilir. > ⚠️ İş yalnızca `Zeyil İsteği` aşamasındayken bu servis çağrılabilir. Başka bir aşamadaki iş için çağrı `500` ile `OfflineEndorsements.StateTransitionFailed` döner. İşin bu aşamaya gelmesi `Poliçe Gerçekleşti` veya `Zeyil Reddedildi` aşamalarından platform tarafında zeyil isteği açılmasıyla olur. Stage kodları için [bknz.](https://docs.insurgateway.com/offline-constants) > 💡 **Transfer fallback:** `endorsementPdf` veya `informationPdf` gönderilmezse, ilgili belge işin transfer dokümanlarından (`ZeyilPdf` / `BilgilendirmeFormu`) otomatik olarak alınır. Belgeler transfer üzerinden zaten yüklenmişse bu alanları göndermeyip `isTransferCompleted` alanını `true` yapmak yeterlidir. --- ### Kimlik Doğrulama Bu uç nokta geçerli bir JWT erişim token'ı gerektirir. Token, `Authentication Login` servisinden alınır ve `Authorization` başlığında gönderilir. | Başlık | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `Authorization` | string | ✅ | `Bearer` biçiminde erişim token'ı. | | `Content-Type` | string | ✅ | `application/json` olmalıdır. | Token'ın aşağıdaki rollerden en az birini taşıması ve `Create` yetkisine sahip olması gerekir: | Rol | Erişim Kapsamı | | --- | --- | | `InsuranceCompanyAPIUser` | Yalnızca kendi sahibi olduğu işlere erişebilir. | | `InsuranceCompanyAPIAdmin` | Token'daki sigorta şirketlerine ait tüm işlere erişebilir. | | `Supervizor` | Token'daki sigorta şirketlerine ait tüm işlere erişebilir. | > ⚠️ İşin `InsuranceCompanyId` değeri token'daki sigorta şirketi listesinde yoksa istek `403` ile `OfflineJobs.JobInsuranceCompanyDenied` döner. `InsuranceCompanyAPIUser` rolündeki kullanıcı, kendi sahibi olmadığı bir iş için `403` ile `OfflineJobs.JobOwnershipDenied` alır. --- ### İstek Parametreleri (Path Variables) | Parametre | Tür | Zorunlu | Min | Max | Açıklama | | --- | --- | --- | --- | --- | --- | | `:jobId` | integer (int32) | ✅ | `1` | `2147483647` | Zeyilin kaydedileceği işin benzersiz kimliği. | --- ### İstek Gövdesi **`MakeEndorsementRequest`** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `productId` | integer (int32) | ✅ | Ürün kimliği. Min `1`, Max `2147483647`. | | `endorsementPolicy` | object | ✅ | Zeyil poliçe bilgileri. Bkz. `EndorsementPolicyRequest`. | | `premium` | object | ⚠️ Koşullu | Prim ve taksit bilgileri. Bkz. `EndorsementPremiumRequest`. Gönderilmezse döviz kuru `0` olarak kaydedilir; **primli zeyillerde gönderilmesi gerekir**. | | `endorsementPdf` | object | ⚠️ Koşullu | Zeyil PDF belgesi. Gönderilmezse işin transfer dokümanı (`ZeyilPdf`) kullanılır. Bkz. `EndorsementFileRequest`. | | `informationPdf` | object | ⚠️ Koşullu | Bilgilendirme formu PDF belgesi. Gönderilmezse işin transfer dokümanı (`BilgilendirmeFormu`) kullanılır. Bkz. `EndorsementFileRequest`. | | `message` | string | — | Zeyile eklenecek serbest metin. Maks. uzunluk `500`. | | `isTransferCompleted` | boolean | — | Zeyilin transfer üzerinden mi yoksa manuel mi tamamlandığını belirtir. Varsayılan `false`. | > ⚠️ `jobId` gövdede **gönderilmez**; yol değişkeninden doldurulur. Gövdeye eklenirse yok sayılır. **`EndorsementPolicyRequest`** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `policyNumber` | string | ✅ | Zeyilin bağlı olduğu poliçe numarası. Boş olamaz. | | `renewalNo` | string | ✅ | Yenileme numarası. Boş olamaz. | | `endorsementNo` | integer (int32) | ✅ | Zeyil numarası. Min `0`, Max `2147483647`. | | `endorsementType` | integer | ✅ | Zeyil türü (`SelectedEndorsementType`). Geçerli değerler için [bknz.](https://docs.insurgateway.com/offline-constants) | | `policyStartDate` | datetime | ✅ | Zeyil başlangıç tarihi. ISO 8601 (`2026-06-01T00:00:00`). | | `policyEndDate` | datetime | ✅ | Zeyil bitiş tarihi. `policyStartDate` değerine eşit veya ondan büyük olmalıdır. | | `processingDate` | datetime | ✅ | Tanzim tarihi. | | `grossPremium` | decimal | ✅ | Brüt prim tutarı. İade/iptal zeyillerinde negatif olabilir. | | `netPremium` | decimal | ✅ | Net prim tutarı. İade/iptal zeyillerinde negatif olabilir. | | `commission` | decimal | ✅ | Komisyon tutarı. İade/iptal zeyillerinde negatif olabilir. | | `installmentNumber` | integer (int16) | ✅ | Taksit sayısı. Min `1`, Max `32767`. | > ⚠️ `endorsementType` enum'u **0 tabanlıdır**. `docs.insurgateway.com` üzerindeki eski tabloda değerler `1–5` olarak listelenmiştir; kodda geçerli olan aralık `0–4`'tür. Aralık dışı bir değer `400` ile `EndorsementType must be a valid endorsement type.` döner. **`EndorsementPremiumRequest`** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `currencyType` | integer | ✅ | Para birimi (`CurrencyType`). Yalnızca `premium` nesnesi gönderildiğinde zorunludur. Geçerli değerler için [bknz.](https://docs.insurgateway.com/offline-constants#currency-type) | | `exchangeRate` | decimal | ✅ | Döviz kuru. Yalnızca `premium` nesnesi gönderildiğinde zorunludur, `0`'dan büyük olmalıdır. TL zeyillerde `1` gönderilir. | | `installmentDetails` | array | — | Taksit detayları listesi. Bkz. `EndorsementInstallmentDetailRequest`. | > 💡 Brüt prim ve komisyonun TL karşılıkları `grossPremium × exchangeRate` ve `commission × exchangeRate` formülüyle sunucu tarafında hesaplanır; ayrıca gönderilmez. Bu nedenle TL zeyillerde de `exchangeRate` alanının `1` olarak gönderilmesi önerilir. **`EndorsementInstallmentDetailRequest`** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `installmentNo` | integer (int16) | ✅ | Taksit sıra numarası. Min `1`, Max `32767`. | | `paymentAmount` | decimal | ✅ | Taksit ödeme tutarı. İade/iptal zeyillerinde negatif olabilir. | | `paymentDate` | datetime | ✅ | Taksit ödeme tarihi. | | `commission` | decimal | — | Taksit komisyonu. Gönderilirse Min `0`. | **`EndorsementFileRequest`** (`endorsementPdf` ve `informationPdf` için ortak) | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `fileName` | string | ✅ | Dosya adı. Nesne gönderildiğinde boş olamaz. Yalnızca uzantısı korunur; dosya sunucuda `{jobId}_{policyNumber}_{renewalNo}_{Policy|Info}_{rastgele}` biçiminde yeniden adlandırılır. | | `contentType` | string | ✅ | MIME türü. Nesne gönderildiğinde boş olamaz. Kayıtta uzantı her hâlükârda `application/pdf` olarak yazılır. | | `base64Content` | string | ✅ | Base64 kodlanmış dosya içeriği. Geçerli base64 olmalıdır (uzunluğu 4'ün katı, çözülebilir). | > ⚠️ `renewalNo` alanı string tipindedir ancak dosya adı üretilirken sayıya çevrilir. Sayısal olmayan bir değer gönderilirse dosya adında `0` olarak yer alır. --- ### İstek Gövdesi Şeması (JSON Schema) ``` json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MakeEndorsementRequest", "type": "object", "required": ["productId", "endorsementPolicy"], "properties": { "productId": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 2147483647 }, "endorsementPolicy": { "$ref": "#/$defs/EndorsementPolicyRequest" }, "premium": { "$ref": "#/$defs/EndorsementPremiumRequest" }, "endorsementPdf": { "$ref": "#/$defs/EndorsementFileRequest" }, "informationPdf": { "$ref": "#/$defs/EndorsementFileRequest" }, "message": { "type": ["string", "null"], "maxLength": 500 }, "isTransferCompleted": { "type": "boolean", "default": false } }, "$defs": { "EndorsementPolicyRequest": { "type": "object", "required": [ "policyNumber", "renewalNo", "endorsementNo", "endorsementType", "policyStartDate", "policyEndDate", "processingDate", "grossPremium", "netPremium", "commission", "installmentNumber" ], "properties": { "policyNumber": { "type": "string", "minLength": 1 }, "renewalNo": { "type": "string", "minLength": 1 }, "endorsementNo": { "type": "integer", "format": "int32", "minimum": 0, "maximum": 2147483647 }, "endorsementType": { "type": "integer", "format": "int32", "minimum": 0, "maximum": 4, "$comment": "SelectedEndorsementType — https://docs.insurgateway.com/offline-constants" }, "policyStartDate": { "type": "string", "format": "date-time" }, "policyEndDate": { "type": "string", "format": "date-time" }, "processingDate": { "type": "string", "format": "date-time" }, "grossPremium": { "type": "number", "format": "decimal" }, "netPremium": { "type": "number", "format": "decimal" }, "commission": { "type": "number", "format": "decimal" }, "installmentNumber": { "type": "integer", "format": "int16", "minimum": 1, "maximum": 32767 } } }, "EndorsementPremiumRequest": { "type": "object", "required": ["currencyType", "exchangeRate"], "properties": { "currencyType": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 7, "$comment": "CurrencyType — https://docs.insurgateway.com/offline-constants#currency-type" }, "exchangeRate": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "installmentDetails": { "type": "array", "items": { "$ref": "#/$defs/EndorsementInstallmentDetailRequest" } } } }, "EndorsementInstallmentDetailRequest": { "type": "object", "required": ["installmentNo", "paymentAmount", "paymentDate"], "properties": { "installmentNo": { "type": "integer", "format": "int16", "minimum": 1, "maximum": 32767 }, "paymentAmount": { "type": "number", "format": "decimal" }, "paymentDate": { "type": "string", "format": "date-time" }, "commission": { "type": ["number", "null"], "format": "decimal", "minimum": 0 } } }, "EndorsementFileRequest": { "type": "object", "required": ["fileName", "contentType", "base64Content"], "properties": { "fileName": { "type": "string", "minLength": 1 }, "contentType": { "type": "string", "minLength": 1 }, "base64Content": { "type": "string", "minLength": 1, "contentEncoding": "base64" } } } } } ``` > 💡 Şemada tanımlı olmayan alanlar sunucu tarafında yok sayılır; istek reddedilmez. **Örnek İstek Gövdesi:** ``` json { "productId": 2321, "message": "Araç plaka değişikliği zeyili", "isTransferCompleted": false, "endorsementPolicy": { "policyNumber": "POL-001", "renewalNo": "1", "endorsementNo": 1, "endorsementType": 1, "policyStartDate": "2026-06-01T00:00:00", "policyEndDate": "2027-06-01T00:00:00", "processingDate": "2026-05-20T00:00:00", "grossPremium": 1000.00, "netPremium": 900.00, "commission": 100.00, "installmentNumber": 1 }, "premium": { "currencyType": 1, "exchangeRate": 1, "installmentDetails": [ { "installmentNo": 1, "paymentAmount": 1000.00, "paymentDate": "2026-06-01T00:00:00", "commission": 100.00 } ] }, "endorsementPdf": { "fileName": "zeyil.pdf", "contentType": "application/pdf", "base64Content": "JVBERi0xLjAK" } } ``` --- ### Başarılı Yanıt (204 No Content) Zeyil kaydedildiğinde HTTP `204 No Content` döner ve **yanıt gövdesi boştur**. İş aşaması `Zeyil Gerçekleşti` olarak güncellenir ve platform tarafına `endorsement-made` bildirimi düşer. > 💡 İşlemin sonucunu doğrulamak için `GET /api/offline/jobs/:jobId/actions` çağrılarak oluşan zeyil aksiyonu okunabilir. --- ### Hatalı Yanıt (400 Bad Request) Alan doğrulaması başarısız olduğunda `ApiResponse` zarfı içinde alan bazlı hata listesi döner. | Alan | Tür | Açıklama | | --- | --- | --- | | `Status` | boolean | Hatalarda her zaman `false`. | | `Code` | string | Hata kodu. Doğrulama hatalarında `Validation.General`. | | `Message` | string | Genel hata açıklaması. | | `Response` | array | null | Alan bazlı hata listesi; doğrulama dışındaki hatalarda `null`. | **`Response`** **nesnesi:** | Alan | Tür | Açıklama | | --- | --- | --- | | `Field` | string | Hatalı alanın yolu. İç içe nesnelerde `EndorsementPolicy.PolicyNumber` biçimindedir. | | `Message` | string | Alanın doğrulama hata mesajı. | **Örnek Hatalı Yanıt:** ``` json { "Status": false, "Code": "Validation.General", "Message": "One or more validation errors occurred", "Response": [ { "Field": "ProductId", "Message": "ProductId is required." }, { "Field": "EndorsementPolicy.PolicyNumber", "Message": "PolicyNumber is required." }, { "Field": "EndorsementPolicy.InstallmentNumber", "Message": "InstallmentNumber must be greater than 0." } ] } ``` > ⚠️ Model binding hataları (örneğin `endorsementNo` alanına metin gönderilmesi veya bozuk JSON) doğrulamadan **önce** oluşur ve `ApiResponse` zarfı yerine düz metin bir gövdeyle `400` döner. Bu yüzden istemci tarafında 400 yanıtları ayrıştırılırken gövdenin JSON olmayabileceği hesaba katılmalıdır. --- ### Hatalı Yanıt (401 Unauthorized) Token gönderilmediğinde, geçersiz olduğunda veya süresi dolduğunda HTTP `401 Unauthorized` döner. Yanıt gövdesi boştur; `WWW-Authenticate` başlığı hatanın nedenini taşır. Süresi dolmuş token `Refresh Token` servisi ile yenilenmelidir. --- ### Hatalı Yanıt (403 Forbidden) Token geçerli olduğu hâlde yetki kapsamı yetersiz olduğunda döner. | Kod | Mesaj | Oluşma Nedeni | | --- | --- | --- | | `OfflineUsers.InsuranceCompanyNotFound` | No valid insurance company assignment found in token. | Token'da sigorta şirketi ataması yok. | | `OfflineUsers.UserIdentityNotResolved` | User identity could not be resolved from token. | Token'dan kullanıcı kimliği çözülemedi. | | `OfflineJobs.JobInsuranceCompanyDenied` | You do not have permission to access jobs of this insurance company. | İşin sigorta şirketi token kapsamı dışında. | | `OfflineJobs.JobOwnershipDenied` | You do not have permission to access this job. | `InsuranceCompanyAPIUser` rolündeki kullanıcı işin sahibi değil. | **Örnek Hatalı Yanıt:** ``` json { "Status": false, "Code": "OfflineJobs.JobInsuranceCompanyDenied", "Message": "You do not have permission to access jobs of this insurance company.", "Response": null } ``` --- ### Hatalı Yanıt (404 Not Found) Verilen `:jobId` ile bir iş bulunamadığında döner. | Kod | Mesaj | | --- | --- | | `OfflineJobs.JobNotFound` | No job found for the requested JobId: {jobId}. | **Örnek Hatalı Yanıt:** ``` json { "Status": false, "Code": "OfflineJobs.JobNotFound", "Message": "No job found for the requested JobId: 999999.", "Response": null } ``` --- ### Hatalı Yanıt (500 Internal Server Error) State machine geçişi sırasında oluşan iş kuralı ihlalleri ve beklenmeyen hatalar bu kodla döner. | Kod | Mesaj | Oluşma Nedeni | | --- | --- | --- | | `OfflineEndorsements.StateTransitionFailed` | Endorsement state transition failed: {detay} | İş kuralı ihlali. En sık nedeni, işin `Zeyil İsteği` aşamasında olmamasıdır. | | `JobState.TransitionError` | An unexpected error occurred during job state transition. | Beklenmeyen sistem hatası. | Aşağıdaki örnek, işi `Poliçe Gerçekleşti` aşamasındayken (henüz zeyil isteği açılmamışken) bu servisin çağrılması durumunda döner: ``` json { "Status": false, "Code": "OfflineEndorsements.StateTransitionFailed", "Message": "Endorsement state transition failed: 'Poliçe Gerçekleşti' aşamasından 'Zeyil Gerçekleşti' aşamasına geçiş yapılamaz. Bu aşamadan yalnızca şu aşamalara geçiş yapılabilir: Zeyil İsteği, Mesaj, Toplu Prim İsteği, Kurum İçi Bilgi Bekleniyor, Kurum Dışı Bilgi Bekleniyor, Bilgi Bekleniyor İptal.", "Response": null } ``` > ⚠️ `OfflineEndorsements.StateTransitionFailed` bir iş kuralı ihlalidir; `500` dönmesine rağmen **isteği aynen tekrarlamak sonucu değiştirmez**. Hata mesajındaki aşama bilgisi okunarak işin doğru aşamada olup olmadığı kontrol edilmelidir.

Authentication

AuthorizationBearer

Bearer authentication of the form Bearer <token>, where token is your auth token.

Path parameters

jobIdintegerRequired

Zeyilin kaydedileceği işin benzersiz kimliği.

Headers

AuthorizationstringOptional

Request

This endpoint expects an object.

Response

No Content

Errors

400
Bad Request Error
403
Forbidden Error
404
Not Found Error
500
Internal Server Error