Make Policy

## Make Policy Sigorta şirketinin, `PolicyRequested` aşamasındaki bir iş (job) için ürettiği poliçeyi platforma kaydeder. İstek başarılı olduğunda `PolicyMade` state geçişi tetiklenir; poliçe, prim ve vade planı kaydedilir, poliçe/bilgilendirme PDF'leri işe eklenir ve ilgili taraflara bildirim e-postası gönderilir. --- ### Uç Nokta (Endpoint) `POST {{baseUrl}}/api/offline/jobs/:jobId/policies` --- ### Kullanım Bu servis, platformdan gelen poliçeleşme talebinin sigorta şirketi tarafındaki karşılığıdır. Önerilen akış: 1. `Authentication Login` servisinden token alınır. 2. `GET /api/offline/jobs` ile `PolicyRequested` aşamasındaki işler listelenir. 3. `GET /api/offline/jobs/:jobId/request-details` ile işin `ProductId`, talep edilen ödeme türü ve taksit sayısı okunur. 4. Poliçe sigorta şirketi sisteminde üretilir. 5. Bu servis çağrılarak poliçe numarası, prim tutarları ve PDF'ler platforma iletilir. 6. `201 Created` dönerse iş `PolicyMade` aşamasına geçmiştir; sonraki adım zeyil akışıdır (`EndorsementRequested`). > 💡 `grossPremium`, `netPremium` ve `commission` değerleri, daha önce teklifte sunulan prim ile **birebir aynı** olmalıdır; aksi hâlde `JobState.PremiumMismatch` alınır. (Acente bazında prim doğrulaması kapatılmışsa bu kontrol atlanır.) > 💡 `premium` bloğu yalnızca platformda kayıtlı prim/vade planının **yerine geçmesi** isteniyorsa gönderilir. Gönderilmezse teklif aşamasında kaydedilen prim ve taksit planı kullanılır, taksit tarihleri poliçe başlangıç tarihinden itibaren aylık olarak yeniden üretilir. > ⚠️ İş `PolicyRequested` aşamasında değilse state machine geçişe izin vermez ve istek `500 Internal Server Error` / `JobState.UnknownBusinessRule` ile sonuçlanır. --- ### 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 <token>` biçiminde erişim token'ı. | | `Content-Type` | string | ✅ | `application/json` olmalıdır. | Token'ın `InsuranceCompanyAPIUser`, `InsuranceCompanyAPIAdmin` veya `Supervizor` rollerinden en az birini ve `Create` yetkisini taşıması gerekir. `InsuranceCompanyAPIUser` yalnızca kendi üzerine atanmış işlerde işlem yapabilir; `InsuranceCompanyAPIAdmin` ve `Supervizor` şirket kapsamındaki tüm işlerde işlem yapabilir. --- ### İstek Parametreleri (Path Variables) | Parametre | Tür | Zorunlu | Min | Max | Açıklama | | --- | --- | --- | --- | --- | --- | | `jobId` | integer | ✅ | 1 | 2147483647 | Poliçesi kaydedilecek işin benzersiz kimliği. | > ⚠️ `jobId` yalnızca yoldan alınır. Gövdede `jobId` göndermek etkisizdir; sunucu bu alanı her zaman yol parametresiyle ezer. --- ### İstek Gövdesi | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `productId` | integer | ✅ | Poliçenin üretildiği ürünün kimliği. Sıfırdan büyük olmalıdır. İşin `request-details` yanıtındaki ürün kimliğiyle eşleşmelidir. | | `policyNumber` | string | ✅ | Sigorta şirketinin verdiği poliçe numarası. | | `renewalNo` | integer | ✅ | Poliçenin yenileme numarası. Sıfır veya daha büyük olmalıdır. | | `policyStartDate` | string (date-time) | ✅ | Poliçe başlangıç tarihi. | | `policyEndDate` | string (date-time) | ✅ | Poliçe bitiş tarihi. `policyStartDate` değerinden büyük olmalıdır. | | `processingDate` | string (date-time) | ✅ | Poliçe tanzim tarihi. | | `grossPremium` | number | ✅ | Poliçe brüt primi. Sıfırdan büyük olmalıdır. | | `netPremium` | number | ✅ | Poliçe net primi. Sıfırdan büyük olmalıdır. | | `commission` | number | ✅ | Poliçe komisyon tutarı. Sıfır veya daha büyük olmalıdır. | | `currencyType` | integer | ✅ | Poliçe para birimi (`CurrencyType`). Geçerli değerler için [bknz.](https://docs.insurgateway.com/offline-constants#currency-type) | | `exchangeRate` | number | ✅ | Poliçe tanzim anındaki döviz kuru. `currencyType` = TL ise **tam olarak `1`**, diğer para birimlerinde **1'den büyük** olmalıdır. | | `isTransferCompleted` | boolean | — | Poliçenin transfer akışıyla kaydedilip kaydedilmediğini belirtir. Varsayılan `false`. | | `message` | string | — | Poliçeye iliştirilen serbest not. En fazla 500 karakter. | | `premium` | object | — | Prim ve vade planı bilgisi. Gönderilirse platformda kayıtlı prim yerine bu bilgi kullanılır. Bkz. `premium` nesnesi. | | `policyPdf` | object | — | Poliçe PDF dokümanı. Bkz. `PolicyFileRequest` nesnesi. | | `informationPdf` | object | — | Bilgilendirme formu PDF dokümanı. Bkz. `PolicyFileRequest` nesnesi. | | `resultKeySets` | array | — | Sigorta şirketinin poliçeyle birlikte döndürdüğü sonuç alanları. Bkz. `resultKeySets` nesnesi. | **`premium` nesnesi** (gönderilirse aşağıdaki alanların doğrulaması uygulanır): | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `paymentOptionType` | integer | ✅ | Ödeme seçeneği türü (`PaymentType`). Geçerli değerler için [bknz.](https://docs.insurgateway.com/offline-constants#payment-type) Platformun talep ettiği ödeme türüyle eşleşmelidir. | | `currencyType` | integer | ✅ | Prim para birimi (`CurrencyType`). Geçerli değerler için [bknz.](https://docs.insurgateway.com/offline-constants#currency-type) | | `installmentNumber` | integer | ✅ | Taksit sayısı. Sıfırdan büyük olmalı ve platformun talep ettiği taksit sayısıyla eşleşmelidir. | | `grossPremium` | number | ✅ | Brüt prim. Sıfırdan büyük olmalıdır. Vade planındaki `paymentAmount` toplamına eşit olmalıdır. | | `netPremium` | number | ✅ | Net prim. Sıfırdan büyük olmalıdır. | | `commission` | number | ✅ | Komisyon tutarı. Sıfır veya daha büyük olmalı ve vade planındaki komisyon toplamından küçük olmamalıdır. | | `premiumInstallmentDetails` | array | ⚠️ Koşullu | Vade planı. `installmentNumber` 1'den büyükse zorunludur ve boş olamaz. | | `isInstallmentsEqual` | boolean | — | Taksitlerin eşit olup olmadığını belirtir. Varsayılan `false`. | | `firstInstallmentRate` | integer | — | İlk taksit oranı. Gönderilirse 1–100 aralığında olmalıdır. | | `exchangeRate` | number | — | Prim için döviz kuru. | | `installmentExplanation` | string | — | Vade planı açıklaması. | | `grossPremiumTL` | number | — | Kullanılmaz; gönderilse de yok sayılır. TL karşılıkları `grossPremium × exchangeRate` ile sunucuda hesaplanır. | | `commissionTL` | number | — | Kullanılmaz; gönderilse de yok sayılır. | **`premiumInstallmentDetails` nesnesi:** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `installmentNumber` | integer | ✅ | Taksit planının toplam taksit sayısı. Sıfırdan büyük olmalıdır. | | `installmentNo` | integer | ✅ | Taksitin sıra numarası. Sıfırdan büyük olmalıdır. | | `paymentAmount` | number | ✅ | Taksit tutarı. Sıfırdan büyük olmalıdır. | | `commission` | number | ✅ | Taksite ait komisyon tutarı. Sıfır veya daha büyük olmalıdır. | | `paymentDate` | string (date-time) | ✅ | Taksitin ödeme tarihi. | **`PolicyFileRequest` nesnesi** (`policyPdf` ve `informationPdf`): | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `fileName` | string | ✅ | Dosya adı. `.pdf` uzantısıyla bitmelidir. | | `base64Content` | string | ✅ | Base64 kodlanmış dosya içeriği. Çözüldüğünde `%PDF` imzasıyla başlayan geçerli bir PDF olmalıdır. | | `contentType` | string | — | Yok sayılır; sunucu içerik türünü her zaman `application/pdf` olarak atar. | > ⚠️ Sunucu, kaydedilen dosyanın adını `{jobId}_{policyNumber}_{renewalNo}_{DokümanTipi}_{rastgele}` biçiminde yeniden üretir. Gönderdiğiniz `fileName` yalnızca uzantı için kullanılır. **`resultKeySets` nesnesi:** | Parametre | Tür | Zorunlu | Açıklama | | --- | --- | --- | --- | | `id` | integer | — | Alanın (key) benzersiz kimliği. | | `keyName` | string | — | Alanın adı. | | `keyValue` | array (string) | — | Alana ait değer listesi. | **Örnek İstek:** ```json { "productId": 41, "policyNumber": "1002340019", "renewalNo": 0, "policyStartDate": "2026-08-15T00:00:00", "policyEndDate": "2027-08-15T00:00:00", "processingDate": "2026-08-10T00:00:00", "grossPremium": 12500.75, "netPremium": 10500.00, "commission": 1250.00, "currencyType": 1, "exchangeRate": 1, "isTransferCompleted": false, "message": "Poliçe tanzim edilmiştir.", "premium": { "paymentOptionType": 1, "currencyType": 1, "isInstallmentsEqual": true, "installmentNumber": 2, "firstInstallmentRate": 50, "grossPremium": 12500.75, "netPremium": 10500.00, "commission": 1250.00, "exchangeRate": 1, "installmentExplanation": "2 eşit taksit", "premiumInstallmentDetails": [ { "installmentNumber": 2, "installmentNo": 1, "paymentAmount": 6250.38, "commission": 625.00, "paymentDate": "2026-08-15T00:00:00" }, { "installmentNumber": 2, "installmentNo": 2, "paymentAmount": 6250.37, "commission": 625.00, "paymentDate": "2026-09-15T00:00:00" } ] }, "policyPdf": { "fileName": "policy.pdf", "base64Content": "JVBERi0xLjQKJeLjz9M..." }, "informationPdf": { "fileName": "information.pdf", "base64Content": "JVBERi0xLjQKJeLjz9M..." }, "resultKeySets": [ { "id": 1, "keyName": "PolicyNumber", "keyValue": ["1002340019"] } ] } ``` --- ### İstek Gövdesi Şeması (JSON Schema) ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CreatePolicyRequest", "type": "object", "required": [ "productId", "policyNumber", "renewalNo", "policyStartDate", "policyEndDate", "processingDate", "grossPremium", "netPremium", "commission", "currencyType", "exchangeRate" ], "properties": { "productId": { "type": "integer", "format": "int32", "exclusiveMinimum": 0, "maximum": 2147483647 }, "policyNumber": { "type": "string", "minLength": 1 }, "renewalNo": { "type": "integer", "format": "int32", "minimum": 0, "maximum": 2147483647 }, "policyStartDate": { "type": "string", "format": "date-time" }, "policyEndDate": { "type": "string", "format": "date-time", "$comment": "policyStartDate değerinden büyük olmalıdır." }, "processingDate": { "type": "string", "format": "date-time" }, "grossPremium": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "netPremium": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "commission": { "type": "number", "format": "decimal", "minimum": 0 }, "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 }, "isTransferCompleted": { "type": "boolean", "default": false }, "message": { "type": ["string", "null"], "maxLength": 500 }, "premium": { "$ref": "#/$defs/PremiumEntryRequest" }, "policyPdf": { "$ref": "#/$defs/PolicyFileRequest" }, "informationPdf": { "$ref": "#/$defs/PolicyFileRequest" }, "resultKeySets": { "type": "array", "items": { "$ref": "#/$defs/KeySetRequest" } } }, "allOf": [ { "if": { "properties": { "currencyType": { "const": 1 } }, "required": ["currencyType"] }, "then": { "properties": { "exchangeRate": { "const": 1 } } }, "else": { "properties": { "exchangeRate": { "exclusiveMinimum": 1 } } } } ], "$defs": { "PremiumEntryRequest": { "type": "object", "required": [ "paymentOptionType", "currencyType", "installmentNumber", "grossPremium", "netPremium", "commission" ], "properties": { "paymentOptionType": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 3, "$comment": "PaymentType — https://docs.insurgateway.com/offline-constants#payment-type" }, "currencyType": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 7, "$comment": "CurrencyType — https://docs.insurgateway.com/offline-constants#currency-type" }, "isInstallmentsEqual": { "type": "boolean", "default": false }, "firstInstallmentRate": { "type": ["integer", "null"], "format": "int16", "minimum": 1, "maximum": 100 }, "installmentNumber": { "type": "integer", "format": "int16", "exclusiveMinimum": 0, "maximum": 32767 }, "grossPremium": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "netPremium": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "commission": { "type": "number", "format": "decimal", "minimum": 0 }, "grossPremiumTL": { "type": ["number", "null"], "format": "decimal", "$comment": "Sunucu tarafında kullanılmaz." }, "commissionTL": { "type": ["number", "null"], "format": "decimal", "$comment": "Sunucu tarafında kullanılmaz." }, "exchangeRate": { "type": ["number", "null"], "format": "decimal" }, "installmentExplanation": { "type": ["string", "null"] }, "premiumInstallmentDetails": { "type": "array", "items": { "$ref": "#/$defs/PremiumInstallmentDetailRequest" } } }, "allOf": [ { "if": { "properties": { "installmentNumber": { "exclusiveMinimum": 1 } }, "required": ["installmentNumber"] }, "then": { "required": ["premiumInstallmentDetails"], "properties": { "premiumInstallmentDetails": { "minItems": 1 } } } } ] }, "PremiumInstallmentDetailRequest": { "type": "object", "required": ["installmentNumber", "installmentNo", "paymentAmount", "commission", "paymentDate"], "properties": { "installmentNumber": { "type": "integer", "format": "int16", "exclusiveMinimum": 0, "maximum": 32767 }, "installmentNo": { "type": "integer", "format": "int16", "exclusiveMinimum": 0, "maximum": 32767 }, "paymentAmount": { "type": "number", "format": "decimal", "exclusiveMinimum": 0 }, "commission": { "type": "number", "format": "decimal", "minimum": 0 }, "paymentDate": { "type": "string", "format": "date-time" } } }, "PolicyFileRequest": { "type": "object", "required": ["fileName", "base64Content"], "properties": { "fileName": { "type": "string", "minLength": 5, "pattern": "(?i)\\.pdf$" }, "base64Content": { "type": "string", "minLength": 1, "contentEncoding": "base64", "contentMediaType": "application/pdf", "$comment": "Çözüldüğünde %PDF imzasıyla başlamalıdır." }, "contentType": { "type": ["string", "null"], "$comment": "Yok sayılır; sunucu application/pdf atar." } } }, "KeySetRequest": { "type": "object", "properties": { "id": { "type": "integer", "format": "int32" }, "keyName": { "type": ["string", "null"] }, "keyValue": { "type": ["array", "null"], "items": { "type": "string" } } } } } } ``` > 💡 Şemada `additionalProperties: false` bilinçli olarak yoktur: API bilinmeyen alanları yok sayar, isteği reddetmez. --- ### Başarılı Yanıt (201 Created) Poliçe başarıyla kaydedildiğinde HTTP `201 Created` döner. **Yanıt gövdesi yoktur.** Bu noktada sunucu tarafında gerçekleşenler: | Tablo / Sistem | İşlem | | --- | --- | | `Policies` | Poliçe kaydı eklenir (`ProducedChannel = Offline`). | | `Premiums` / `PremiumInstallmentDetails` | Prim ve vade planı yeniden yazılır. | | `Jobs` | `CurrentStage = PolicyMade` olarak güncellenir. | | `JobActions` | `PolicyMade` tipinde yeni aksiyon eklenir. | | `OperationWatch` | `Success = true`, `Complete = true` işaretlenir. | | Platform | Poliçe, prim ve aksiyon bilgisi platform servisine yazılır. | | Doküman / E-posta | PDF'ler arka plan işiyle kaydedilir, bildirim e-postası gönderilir. | --- ### Hatalı Yanıt (400 Bad Request) Hatalar `ApiResponse` sarmalayıcısıyla döner: | Alan | Tür | Açıklama | | --- | --- | --- | | `Status` | boolean | Hata durumunda her zaman `false`. | | `Code` | string | Hata kodu. Alan bazlı doğrulama hatalarında `Validation.General`, diğerlerinde ilgili iş kuralı kodu. | | `Message` | string | Hata açıklaması. | | `Response` | array \| null | Doğrulama hatalarında `{ Field, Message }` listesi; diğer hatalarda `null`. | **Alan doğrulama hatası:** ```json { "Status": false, "Code": "Validation.General", "Message": "One or more validation errors occurred", "Response": [ { "Field": "PolicyNumber", "Message": "PolicyNumber is required." }, { "Field": "ExchangeRate", "Message": "ExchangeRate must be 1 for TL." } ] } ``` **İş kuralı hataları:** | `Code` | Ne zaman oluşur | | --- | --- | | `JobState.PremiumMismatch` | Poliçe brüt/net/komisyon tutarı, teklifte sunulan prim ile aynı değil. | | `JobState.InstallmentTotalMismatch` | `premiumInstallmentDetails` toplamı brüt prime eşit değil ya da komisyon toplamı komisyon primini aşıyor. | | `JobState.PaymentOptionMismatch` | Gönderilen `paymentOptionType`, platformun talep ettiği ödeme türüyle eşleşmiyor. | | `JobState.InstallmentNumberMismatch` | Gönderilen `installmentNumber`, teklifte sunulan taksit seçenekleri arasında yok. | ```json { "Status": false, "Code": "JobState.PremiumMismatch", "Message": "Premium values do not match between policy and proposal: Poliçe ve Teklif'te alınan bilgilerde brüt prim farkı oluşmuştur. Teklif ve Poliçe brüt priminin doğru olduğundan eminiz olunuz. Teklif Brüt Prim: 12.400,00 Poliçe Brüt Prim: 12.500,75", "Response": null } ``` --- ### 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.** > 💡 Token'ın süresi dolduysa yanıtta `Token-Expired: true` başlığı bulunur. Bu durumda `POST /api/authentication/refreshtoken` ile yeni token alınmalıdır. --- ### Hatalı Yanıt (403 Forbidden) | `Code` | Ne zaman oluşur | | --- | --- | | `OfflineUsers.InsuranceCompanyNotFound` | Token'da geçerli bir sigorta şirketi ataması yok. | | `OfflineUsers.UserIdentityNotResolved` | Token'dan kullanıcı kimliği çözümlenemedi. | | `OfflineJobs.JobInsuranceCompanyDenied` | İş, token'daki sigorta şirketi kapsamının dışında. | | `OfflineJobs.JobOwnershipDenied` | `InsuranceCompanyAPIUser` rolündeki kullanıcı, kendisine ait olmayan bir işte işlem yapmaya çalıştı. | ```json { "Status": false, "Code": "OfflineJobs.JobOwnershipDenied", "Message": "You do not have permission to access this job.", "Response": null } ``` --- ### Hatalı Yanıt (404 Not Found) | `Code` | Ne zaman oluşur | | --- | --- | | `OfflineJobs.JobNotFound` | Verilen `jobId` ile eşleşen iş kaydı yok. | | `JobState.OperationWatchNotFound` | Teklif ve ürün için poliçe operasyon kaydı bulunamadı. | | `JobState.PremiumNotFound` | Teklifte, talep edilen taksit ve ödeme türüne ait prim kaydı bulunamadı (ve istekte `premium` gönderilmedi). | | `JobState.PlatformUserNotFound` | Aksiyonu karşılayacak platform kullanıcısı bulunamadı. | ```json { "Status": false, "Code": "OfflineJobs.JobNotFound", "Message": "No job found for the requested JobId: 999999.", "Response": null } ``` --- ### Hatalı Yanıt (409 Conflict) | `Code` | Ne zaman oluşur | | --- | --- | | `JobState.PolicyMadeByOtherCompany` | Teklif başka bir sigorta şirketi tarafından poliçeleştirilmiş. | | `JobState.PolicyAlreadyExists` | Aynı poliçe/zeyil/yenileme numarasıyla kayıt zaten var ya da ürün için poliçe bilgisi mevcut. | ```json { "Status": false, "Code": "JobState.PolicyAlreadyExists", "Message": "A policy already exists for job 12345.", "Response": null } ``` --- ### Hatalı Yanıt (500 Internal Server Error) | `Code` | Ne zaman oluşur | | --- | --- | | `JobState.PlatformServiceFailure` | Poliçe, prim ve taksit bilgileri platform servisine yazılamadı. | | `JobState.UnknownBusinessRule` | Eşlenmemiş bir iş kuralı ihlali oluştu. İş `PolicyRequested` aşamasında değilken bu servis çağrıldığında da bu kod döner. | | `JobState.TransitionError` | State geçişi sırasında beklenmeyen bir hata oluştu. | ```json { "Status": false, "Code": "JobState.UnknownBusinessRule", "Message": "An unknown business rule error occurred: 'Poliçe Yapıldı' aşamasından 'Poliçe Yapıldı' aşamasına geçiş yapılamaz. Bu aşamadan yalnızca şu aşamalara geçiş yapılabilir: Mesaj, Zeyil Talebi.", "Response": null } ```

Authentication

AuthorizationBearer

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

Path parameters

jobIdintegerRequired

Poliçesi kaydedilecek işin benzersiz kimliği.

Headers

AuthorizationstringOptional

Request

This endpoint expects an object.

Response

Created

Errors

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