Insurance
API Path
Orders and Payment Binding

Orders and Payment Binding

An order is the purchase of the quote option the buyer confirmed. Premium collection, policy, refund and document processes are tracked on the order. The order's status axes and overall status: Concepts and Statuses › Order statuses.

Authentication, Idempotency-Key and the error envelope: Flows.

Creating an order: POST /api/v1/insurance/orders

Idempotency-Key is required. Creating an order sends no request to the provider and moves no money; it records the option and the buyer's consent.

FieldTypeRequiredDescription
quoteIdstringYesID of the option the buyer confirmed (insq_…).
merchantOrderIdstringNoYour own order number, up to 128 characters. If omitted, the value from the quote is used. If the quote also has a value, both must be the same.
consent.termsVersionstringYesThe option's terms.version value, exactly as received.
consent.termsSha256stringYesThe option's terms.sha256 value, exactly as received.
consent.acceptedAtstringYesThe moment the buyer gave consent. ISO 8601 with a time zone; cannot be in the future.

Consent

  • consent records that the buyer accepts the option's terms and consents to their details being shared with the provider for the insurance.
  • The terms values must equal the option's. The terms of another option or of an old quote do not count as accepted: the request returns 422 insurance.validation.invalid (field: consent.termsSha256, reason: terms_mismatch).
  • acceptedAt can be at most a few minutes ahead of server time; a later time is rejected.

Rules

  • The option must be valid: an expired option returns 409 insurance.quote.expired.
  • Only one order can be created from an option. A second order returns 409 insurance.order.state_conflict (reason: quote_already_ordered).
  • Only quotes you got from the API can be turned into orders.
{
  "quoteId": "insq_<32 hex characters>",
  "merchantOrderId": "order-1001",
  "consent": {
    "termsVersion": "<the option's terms.version value>",
    "termsSha256": "<the option's terms.sha256 value>",
    "acceptedAt": "2025-12-20T10:15:00+03:00"
  }
}
source lunixi-sign.sh
BODY='<order request, compact JSON>'
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"

A successful request returns 201 and the order object in data. In a new order paymentMode is NO_PAYMENT, collection is NOT_STARTED and policy is NOT_REQUESTED.

The next step is collecting the premium: Premium and Payment.

Order object

FieldTypeDescription
orderIdstringOrder ID (inso_…). In a Lunixi payment, this is the premium item's id.
quoteIdstringThe option the order was created from.
insuranceTypestringInsurance type.
surfacestringWhere the order was created: MERCHANT_API or CHECKOUT_FORM.
statusstringOverall status; derived from the four axes. See Concepts › Overall status.
collectionStatusstringCollection axis.
policyStatusstringPolicy axis.
refundStatusstringRefund axis.
documentStatusstringDocument axis.
paymentModestringHow the premium was paid: NO_PAYMENT (not bound yet), LUNIXI_PAYMENT (bound to a Lunixi payment) or EXTERNAL_PAYMENT (paid outside Lunixi).
premiumCollectedBystringWho collects the premium: MERCHANT when you collect it, PROVIDER when your provider collects it (Provider Collection).
premiumAmountintegerPremium, in minor units.
currencystringCurrency, ISO 4217.
paymentIntentIdstring or nullID of the bound Lunixi payment.
merchantOrderIdstring or nullYour own order number.
providerobjectThe provider: code, name, logoUrl and connectionId, the ID of your connection the policy is issued through. You reconcile with your provider using this information.
basketItemIdsstring[]The insured basket items.
policiesarrayPolicies per item; fields below.
errorCodestring or nullLunixi code of the last error on the collection or policy side, e.g. insurance.premium.not_captured, insurance.payment.declined, insurance.policy.issue_failed.
refundErrorCodestring or nullLunixi code of the last refund attempt, e.g. insurance.refund.rejected.
refundedAtstring or nullThe moment the refund was finalized.
nextActionobject or nullThe step the buyer must take while the provider collects the premium; null when no step is pending. See Provider Collection › Buyer action.
createdAtstringCreation time, ISO 8601.
updatedAtstringLast change time, ISO 8601.

policies[]:

FieldTypeDescription
policyIdstringPolicy ID (insp_…). You get the document with this ID: Policy Document.
basketItemIdstringThe basket item the policy insures.
policyNumberstring or nullThe number on the policy document. null until the policy is issued.
policyStatusstringStatus of this policy; the values are the same as the policy axis.
documentStatusstringDocument status of this policy.

Policies are created per item after the premium is collected. In a new order policies is an empty array.

Listing: GET /api/v1/insurance/orders

Returns your orders newest first, in cursor-based pages. Orders created in the Checkout Form are also listed (surface: CHECKOUT_FORM).

Query parameterTypeDescription
limitintegerRecords per page, 1-100. Default 25.
cursorstringpageInfo.nextCursor from the previous response. Not sent for the first page.
paymentIntentIdstring (UUID)Only orders bound to this Lunixi payment.
merchantOrderIdstringOnly orders carrying this order number.

In the response, the orders are in the data.items array; the pagination information is in pageInfo. A malformed cursor returns 422 insurance.validation.invalid (field: cursor).

source lunixi-sign.sh
REQ_PATH="/api/v1/insurance/orders?limit=25&merchantOrderId=order-1001"
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"

Retrieving: GET /api/v1/insurance/orders/{orderId}

Returns a single order; data is the order object. You track the order's policy and document status with this endpoint. If the ID is not found or belongs to another account, 404 insurance.order.not_found is returned.

Binding to a payment: POST /api/v1/insurance/orders/{orderId}/bind-payment

Binds the order to the Lunixi payment that carries the premium in its basket. Idempotency-Key is optional.

FieldTypeRequiredDescription
paymentIntentIdstring (UUID)YesLunixi payment ID.

Binding is checked in this order:

  1. The order must have been created through the API, must not be bound to another payment and must not have been paid outside Lunixi. An order whose collection has started cannot be bound.
  2. The order's option must be valid (409 insurance.quote.expired).
  3. The payment must have been created with insured items (412 insurance.order.payment_not_recorded).
  4. The payment's currency must equal the order's.
  5. The payment's insured items must be the same as the quoted items (409 insurance.quote.stale).
  6. The payment's basket must contain the premium item exactly once: id is the order ID, itemType is VIRTUAL, price is the premium (409 insurance.order.premium_item_mismatch). If the provider collects the premium (premiumCollectedBy: PROVIDER), the basket has no premium item: Provider Collection.

Binding the same payment again returns the order as it is. In a successful response paymentMode becomes LUNIXI_PAYMENT. The premium item and the payment request: Premium and Payment › Lunixi payment.

details.reason in an insurance.order.premium_item_mismatch response:

reasonMeaning
missingThe basket has no premium item with the order ID, or has more than one.
amountThe premium item's price differs from the premium.
item_typeThe premium item's itemType is not VIRTUAL.
not_allowedThe provider collects the premium; the basket must not contain a premium item with the order ID.

Reporting a premium collected outside Lunixi: POST /api/v1/insurance/orders/{orderId}/confirm-payment

If you collected the premium outside Lunixi, you report the payment. Lunixi forwards the notification to your provider through your connection. Idempotency-Key is required.

FieldTypeRequiredDescription
payment.externalPaymentIdstringYesThe payment ID on your side; 1-128 printable ASCII characters.
payment.paidAmountintegerYesAmount paid, in minor units. Must equal the order's premium.
payment.paidCurrencystringYesCurrency, ISO 4217. Must equal the order's currency.
payment.paidAtstringYesThe moment of payment. ISO 8601 with a time zone; cannot be in the future.
payment.paymentProviderstringNoThe institution you took the payment with; up to 64 characters, informational.
  • If the order is bound to a Lunixi payment, the notification is not accepted (409 insurance.order.state_conflict, reason: lunixi_payment).
  • The order's option must be valid (409 insurance.quote.expired).
  • If the amount or the currency does not match, 422 insurance.validation.invalid is returned (reason: premium_amount_mismatch or premium_currency_mismatch).
  • In a successful response paymentMode becomes EXTERNAL_PAYMENT and collection becomes COLLECTED. Repeating with the same externalPaymentId returns the order as it is; a different ID returns 409 (reason: external_payment).
{
  "payment": {
    "externalPaymentId": "pay-1001",
    "paidAmount": 3980,
    "paidCurrency": "TRY",
    "paidAt": "2025-12-20T10:16:00+03:00"
  }
}

The amount is an example; paidAmount is the order's premiumAmount value.

Requesting the policy: POST /api/v1/insurance/orders/{orderId}/issue-policy

Requests the policy after a premium collected outside Lunixi. No body is sent. Idempotency-Key is required.

  • If the premium has not been collected, 412 insurance.premium.not_captured is returned.
  • The response is the state in which the request was recorded: policyStatus PENDING. The policy is issued in the background; track the result through the order endpoint.
  • If the policy was already requested or has a result, the order is returned as it is.
  • If the premium refund has started, the policy cannot be requested (409, reason: refund_started).

You do not need this endpoint for an order bound to a Lunixi payment: the policy is requested automatically when the payment is captured.

State conflict

409 insurance.order.state_conflict means the order's state does not allow the operation. The reason is in details.reason; retrying the same request does not change the result.

reasonMeaning
quote_already_orderedAn order was already created from this option.
not_api_orderThe order was created in the Checkout Form; it cannot be bound to a payment through the API.
already_boundThe order is bound to another payment.
quote_bound_to_other_paymentThe quote was taken with another payment.
external_paymentThe order's premium was reported as paid outside Lunixi.
lunixi_paymentThe order is bound to a Lunixi payment; a payment outside Lunixi cannot be reported.
collection_startedCollection of the premium has started.
collected_by_providerThe provider collects the premium; this operation is not possible.
refund_startedThe premium refund has started or completed.

Reasons specific to the cancellation, refund and document endpoints are on their own pages.

Errors

HTTPcodeWhat to do
400VALIDATION_ERRORFix the format; this error is also returned when Idempotency-Key is missing.
422insurance.validation.invalidFix the fields in details.errors[].
404insurance.quote.not_foundThe option was not found.
404insurance.order.not_foundThe order was not found.
409insurance.quote.expiredThe option has expired; get a new quote.
409insurance.quote.staleThe payment's basket differs from the quote; get a new quote.
409insurance.order.state_conflictSee details.reason; table above.
409insurance.order.premium_item_mismatchFix the premium item; see details.reason.
412insurance.order.payment_not_recordedCreate the payment with insured items.
412insurance.premium.not_capturedThe policy cannot be requested before the premium is collected.
409insurance.idempotency.conflictThe same Idempotency-Key was used with a different request.

Common codes: Flows › Responses and errors.

Related