Insurance-Only Integration
If you take your payments outside Lunixi, or you only want to sell insurance, you integrate insurance on its own, through the API. In this integration you do not create a payment in Lunixi; Lunixi provides the quote, order, policy, document, cancellation and webhook infrastructure.
This page lists every step of the integration in order. The fields and rules of each step are on the linked endpoint page.
| Your situation | Path to use |
|---|---|
| You take the payment outside Lunixi, or you sell insurance only | This page |
| You take the payment with the Lunixi payment form | Checkout Form path |
| You take the payment from your own form with the Lunixi API | API path › Flow linked to a Lunixi payment |
Before you start
- The insurance product must be enabled on your account. The payment product is not required; the insurance endpoints check the insurance product only.
- Your API key must have access to the insurance product. If your key does not carry the insurance product, every request returns
403 PRODUCT_NOT_ENABLED. - Connect your provider in the panel. On the POS Center > Insurance page, add a connection for the provider you have an agreement with, enable the product you will offer and answer Who collects the premium according to your agreement: Provider Connection.
- Turn insurance on and choose the type to offer. In the Insurance product in the panel's left menu, on the General screen, turn on Insurance on and select the API — external collection usage mode; on the Insurance Types screen, enable the type you will offer and save. If insurance is off, no API mode is selected or the type is off, insurance is not offered: Insurance Menu › General.
- Create your webhook endpoint. Create an endpoint with
productCode: INSURANCE_SERVICEfor insurance events: Webhook Events › Subscription. - Test first. Try it with your test key and a connection in the Test environment: Testing.
Flow
… stands for /api/v1/insurance. The branch is set by the option’s premiumCollectedBy; the outcome arrives as the insurance.policy.issued webhook or on the order endpoint.1. Sign your requests
The insurance endpoints accept requests signed with your API key: X-Key-Id, X-Date, X-Nonce, Digest on requests with a body, and X-Signature. The examples on this page use the same shell helper (lunixi_sign): Flows › Authentication.
- Endpoints that create an order or change its state require the
Idempotency-Keyheader: Flows › Idempotency-Key. - If the provider collects the premium, the
/payendpoint you use requires a Bearer access token in addition to the signature: Provider Collection › Authentication.
2. Find the insurance types offered
The eligibility endpoint tells you which insurance you can offer the buyer. It is read-only and sends no request to the provider.
- If the insurance covers a product (a ticket, a device, a vehicle and so on), send the product as a basket item:
POST /api/v1/insurance/products, withcurrencyandcontext.itemsin the body. You do not create a payment in Lunixi; the items only state what the insurance covers. Item format and insurance fields: Basket Items › Insurance fields. - If the insurance is not tied to a product (such as personal accident), call
GET /api/v1/insurance/products?currency=TRY; the response returns the types sold without a basket item.
Do not send paymentIntentId; that field is for the flow linked to a Lunixi payment. Response and the meaning of an empty list: Eligibility.
Get the codes used in type fields (country, city, district, brand, model, occupation and so on) from the reference endpoint: Insurance Types and Schemas › Reference codes.
3. Get a quote
Send the details of the buyer and of what is insured with POST /api/v1/insurance/quotes.
- As the basket source, send the
context.itemsyou sent in step 2. For types sold without a basket item, send neithercontext.itemsnorpaymentIntentId: Selling Without a Basket Item. - Also send the fields needed for the policy in the quote request. The policy is issued with the quote's details; the order and policy requests carry no fields.
- The response returns one or more options. Show the buyer each option's provider, premium, coverage summary and terms; never preselect insurance.
- The option's
premiumCollectedByvalue tells you which path to follow in step 5.
Fields, the option object and validity: Quotes. Type fields: Insurance Types and Schemas.
4. Create an order
When the buyer confirms an option, create an order with POST /api/v1/insurance/orders. The body carries the option's quoteId and the buyer's consent (consent); Idempotency-Key is required.
- Creating an order sends no request to the provider and moves no money.
- A new order has
paymentModeNO_PAYMENT, collectionNOT_STARTEDand policyNOT_REQUESTED. - Do not bind the order to a Lunixi payment;
bind-paymentis not used in this integration.
Fields and rules: Orders and Payment Binding › Creating an order.
5. Collect the premium
If you collect the premium (MERCHANT)
- Take the premium. Collect the order's
premiumAmountin itscurrencythrough your own payment channel. - Report the payment. Report the payment's ID, amount, currency and time with
POST /api/v1/insurance/orders/{orderId}/confirm-payment. The amount and currency must equal the order premium; report before the option expires. Lunixi forwards the notification to your provider through your connection. In the responsepaymentModebecomesEXTERNAL_PAYMENTand collectionCOLLECTED: Reporting a premium collected outside Lunixi. - Request the policy. Call
POST /api/v1/insurance/orders/{orderId}/issue-policywithout a body. In the response the policy isPENDING; the policy is issued in the background: Requesting the policy.
If the provider collects the premium (PROVIDER)
confirm-payment and issue-policy are not used. You have the provider charge the premium with POST /api/v1/insurance/orders/{orderId}/pay; once the premium is charged, the policy is requested automatically.
- Because the order is not bound to a Lunixi payment,
/paydoes not wait for a Lunixi payment to be captured. - If the product charges the premium by card (
CARD), you send the buyer's card details in the body. Only PCI-DSS certified merchants may send raw card data. The card is not stored by Lunixi. - If the product charges the premium on the provider's payment page (
HOSTED), you send no card; you redirect the buyer tonextAction.redirectUrlfrom the response and bring them back to your page withreturnUrl.
Authentication, request, outcomes and errors: Provider Collection.
6. Track the policy
Receive the policy outcome by webhook; when in doubt, read the order with GET /api/v1/insurance/orders/{orderId}.
| Event | What you do |
|---|---|
insurance.policy.issued | The policy is issued. Policy numbers are in data.policies[].policyNumber. |
insurance.policy.document_ready | The document is available; go to step 7. |
insurance.policy.failed | The policy could not be issued for good, or the premium could not be charged. The reason is in data.errorCode. |
insurance.refund.required | The premium was collected but the policy could not be issued; refund the premium (step 8). |
Deduplicate events by x-lunixi-event-id and derive the order's latest state from its status axes, not from the order of events: Webhook Events. Status axes: Concepts and Statuses.
7. Get the document
When the policy is issued, get its document as a PDF with GET /api/v1/insurance/policies/{policyId}/document. policyId is in the order's policies[] array; each insured item has its own policy and document.
- The document is not stored by Lunixi; it is fetched from the provider on every request. If the provider cannot provide it at that moment, the response is
503 insurance.document.unavailable; try again later. - If the product provides them, you get the premium receipt from
/receiptand the certificate from/certificate.
Details: Policy Document.
8. Cancellation and refund
- Cancellation:
POST /api/v1/insurance/orders/{orderId}/cancelopens a cancellation request at the provider for the issued policies. The result is finalized later: the response showsCANCEL_PENDING, andinsurance.policy.cancelledarrives when the provider confirms the cancellation. Cancelling does not refund the premium. - If you collected the premium: you make the refund through your own channel and report it with
POST /api/v1/insurance/orders/{orderId}/refund-premiumby sendingexternalRefund. No money moves in Lunixi; the refund becomesREFUNDEDandinsurance.refund.completedarrives. - If the provider collected the premium: the premium is not refunded through Lunixi;
refund-premiumreturns409(reason: collected_by_provider) for these orders. The refund is part of your provider's cancellation process.
Cancel an in-force policy before refunding its premium. Rules: Cancellation and Premium Refund.
9. Reconciliation
Get the policy and premium report per connection from the API to reconcile with your provider: Reconciliation Report.
Other endpoints
| Need | Page |
|---|---|
| Pass the buyer's details to the provider for types that return no quote | Leads |
| Report a claim for an issued policy | Claims |
| List your orders | Orders and Payment Binding › Listing |
| Every endpoint in one table | Endpoint Reference |
End-to-end example
A ticket cancellation insurance sale for two tickets, with the premium collected by you. Values are examples; replace the values in angle brackets with your own and the personal fields with your buyer's details. Send the body of every request as JSON without whitespace.
Eligibility
source lunixi-sign.sh
BODY='{"currency":"TRY","context":{"items":[{"id":"ticket-1","name":"Izmir-Ankara train ticket","price":50000,"category1":"ticket","itemType":"VIRTUAL","insuranceCategory":"TICKET","insuranceTypes":["TICKET_CANCELLATION"]},{"id":"ticket-2","name":"Izmir-Ankara train ticket","price":50000,"category1":"ticket","itemType":"VIRTUAL","insuranceCategory":"TICKET","insuranceTypes":["TICKET_CANCELLATION"]}]}}'
lunixi_sign POST "/api/v1/insurance/products" "$BODY"
curl -X POST "https://api-gateway.lunixi.com/api/v1/insurance/products" \
-H "Content-Type: application/json" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
--data-raw "$BODY"If data.products returns TICKET_CANCELLATION with basketItemIds, you can offer the insurance.
Quote
The body carries the same items together with the details of the insured and the tickets. Full request: Quotes › Getting a quote.
BODY='<quote request, JSON without whitespace>'
lunixi_sign POST "/api/v1/insurance/quotes" "$BODY"
curl -X POST "https://api-gateway.lunixi.com/api/v1/insurance/quotes" \
-H "Content-Type: application/json" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
--data-raw "$BODY"Show the buyer the data.options[] options. Keep the quoteId, terms.version, terms.sha256 and premiumCollectedBy values of the option the buyer selected.
Order
BODY='{"quoteId":"<quoteId>","merchantOrderId":"order-1001","consent":{"termsVersion":"<terms.version>","termsSha256":"<terms.sha256>","acceptedAt":"<time of the buyer consent, ISO 8601>"}}'
lunixi_sign POST "/api/v1/insurance/orders" "$BODY"
curl -X POST "https://api-gateway.lunixi.com/api/v1/insurance/orders" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: insurance-order-1001" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
--data-raw "$BODY"Keep data.orderId and data.premiumAmount from the response.
Payment report
Report the premium after you collect it through your own channel. The amount is an example; paidAmount is the order's premiumAmount.
REQ_PATH="/api/v1/insurance/orders/<orderId>/confirm-payment"
BODY='{"payment":{"externalPaymentId":"pay-1001","paidAmount":3980,"paidCurrency":"TRY","paidAt":"<payment time, ISO 8601>"}}'
lunixi_sign POST "$REQ_PATH" "$BODY"
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: insurance-confirm-1001" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
--data-raw "$BODY"Policy request
REQ_PATH="/api/v1/insurance/orders/<orderId>/issue-policy"
lunixi_sign POST "$REQ_PATH"
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
-H "Idempotency-Key: insurance-issue-1001" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGNATURE"Outcome and document
Wait for the insurance.policy.issued and insurance.policy.document_ready events, or read the order. Then get the document of each policy:
REQ_PATH="/api/v1/insurance/policies/<policyId>/document"
lunixi_sign GET "$REQ_PATH"
curl "https://api-gateway.lunixi.com$REQ_PATH" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGNATURE" \
-o policy.pdfIf the buyer later changes their mind, cancel the policy with cancel; after insurance.policy.cancelled arrives, refund the premium through your own channel and report it with refund-premium: Cancellation and Premium Refund.
Common errors
| HTTP | code | What to do |
|---|---|---|
403 | PRODUCT_NOT_ENABLED | The insurance product is not enabled on your account or on your API key. |
409 | insurance.quote.expired | The option has expired; get a new quote and create a new order. |
409 | insurance.order.state_conflict | The order does not allow this operation; see details.reason: Orders › State conflict. |
412 | insurance.premium.not_captured | Report the payment with confirm-payment before requesting the policy. |
422 | insurance.validation.invalid | Fix the details.errors[] fields; in the payment report the amount and currency must equal the order premium. |
All codes: Error Codes.
Related
- Endpoint Reference: every insurance endpoint
- Concepts and Statuses: order status axes
- Webhook Events:
insurance.*events - Testing: test connection and test key