## 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.
Request
This endpoint expects an object.