Insurance
Insurance-Only Integration

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 situationPath to use
You take the payment outside Lunixi, or you sell insurance onlyThis page
You take the payment with the Lunixi payment formCheckout Form path
You take the payment from your own form with the Lunixi APIAPI 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_SERVICE for insurance events: Webhook Events › Subscription.
  • Test first. Try it with your test key and a connection in the Test environment: Testing.

Flow

Insurance-only integration flowFlow: get the insurance types, a quote and an order; then either you collect the premium and call confirm-payment and issue-policy, or the provider collects it through pay; the policy issued webhook or the order endpoint gives the outcome, you get the policy document and, if needed, cancel or refund the premium.MERCHANTPROVIDERTypesPOST …/productsQuotePOST …/quotesOrderPOST …/ordersYou collectconfirm-payment · issue-policyProvider collectsPOST …/{orderId}/payPolicy issuedwebhook or orderDocumentGET …/documentCancel · refundif neededLEGENDYOUR CALLOUTCOMEIF NEEDED
… 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.

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, with currency and context.items in 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.items you sent in step 2. For types sold without a basket item, send neither context.items nor paymentIntentId: 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 premiumCollectedBy value 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 paymentMode NO_PAYMENT, collection NOT_STARTED and policy NOT_REQUESTED.
  • Do not bind the order to a Lunixi payment; bind-payment is 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)

  1. Take the premium. Collect the order's premiumAmount in its currency through your own payment channel.
  2. 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 response paymentMode becomes EXTERNAL_PAYMENT and collection COLLECTED: Reporting a premium collected outside Lunixi.
  3. Request the policy. Call POST /api/v1/insurance/orders/{orderId}/issue-policy without a body. In the response the policy is PENDING; 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, /pay does 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 to nextAction.redirectUrl from the response and bring them back to your page with returnUrl.

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}.

EventWhat you do
insurance.policy.issuedThe policy is issued. Policy numbers are in data.policies[].policyNumber.
insurance.policy.document_readyThe document is available; go to step 7.
insurance.policy.failedThe policy could not be issued for good, or the premium could not be charged. The reason is in data.errorCode.
insurance.refund.requiredThe 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 /receipt and the certificate from /certificate.

Details: Policy Document.

8. Cancellation and refund

  • Cancellation: POST /api/v1/insurance/orders/{orderId}/cancel opens a cancellation request at the provider for the issued policies. The result is finalized later: the response shows CANCEL_PENDING, and insurance.policy.cancelled arrives 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-premium by sending externalRefund. No money moves in Lunixi; the refund becomes REFUNDED and insurance.refund.completed arrives.
  • If the provider collected the premium: the premium is not refunded through Lunixi; refund-premium returns 409 (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

NeedPage
Pass the buyer's details to the provider for types that return no quoteLeads
Report a claim for an issued policyClaims
List your ordersOrders and Payment Binding › Listing
Every endpoint in one tableEndpoint 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.pdf

If 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

HTTPcodeWhat to do
403PRODUCT_NOT_ENABLEDThe insurance product is not enabled on your account or on your API key.
409insurance.quote.expiredThe option has expired; get a new quote and create a new order.
409insurance.order.state_conflictThe order does not allow this operation; see details.reason: Orders › State conflict.
412insurance.premium.not_capturedReport the payment with confirm-payment before requesting the policy.
422insurance.validation.invalidFix the details.errors[] fields; in the payment report the amount and currency must equal the order premium.

All codes: Error Codes.

Related