Webhook Events
When the outcome of your insurance orders changes, Lunixi sends insurance.* events to your endpoint: the policy was issued, could not be issued, its document is ready, it was cancelled, a premium refund is required or completed; a claim was passed to the provider or could not be passed; a lead was passed to the provider. The events are the same on the Checkout Form path and on the API path.
Delivery, signature verification and retries are the same for all products: Webhooks.
Events
| Event | When it is sent |
|---|---|
insurance.policy.issued | The order's policies were issued by the provider. |
insurance.policy.failed | The policy could not be issued, finally, or the policy was not requested because the premium could not be collected. The reason is in data.errorCode. |
insurance.refund.required | The premium was collected but the policy could not be issued, finally; the premium has to be refunded to the buyer. |
insurance.policy.document_ready | The documents of the order's issued policies can be retrieved. |
insurance.policy.cancelled | The provider finalized the cancellation of all policies of the order. |
insurance.refund.completed | The premium refund was completed. |
insurance.claim.submitted | A claim was passed to the provider and the provider recorded it. |
insurance.claim.failed | A claim was not accepted by the provider or did not reach the provider. The reason is in data.claim.errorCode. |
insurance.lead.submitted | A lead was passed to the provider and the provider received it. |
insurance.policy.issued
Sent when the order's policies are issued. data.policyStatus becomes ISSUED; the policy numbers are in data.policies[].policyNumber.
The document may not be ready yet at this point (documentStatus: PENDING). When it is ready, insurance.policy.document_ready is sent as well.
The policy outcome may be finalized late. If insurance.policy.failed (and insurance.refund.required) was sent for an order first and the refund has not started yet, insurance.policy.issued is also sent when the policy is issued later. In that case data.refundStatus is NONE; the premium refund is no longer required.
insurance.policy.failed
Sent in three cases:
| Case | data |
|---|---|
| The policy could not be issued, finally. | policyStatus: FAILED_FINAL. errorCode carries the reason, e.g. insurance.policy.issue_failed or insurance.policy.issue_deadline_passed. |
| The payment was cancelled, expired or finally failed before it was captured. | collectionStatus: FAILED, policyStatus: NOT_REQUESTED, errorCode: insurance.premium.not_captured. No refund is needed because no premium was taken. |
| The provider collects the premium and declined the charge. | collectionStatus: FAILED, policyStatus: NOT_REQUESTED, errorCode: insurance.payment.declined. Your payment stays valid. See Provider Collection. |
If the premium was collected, insurance.refund.required is sent at the same time.
insurance.refund.required
Sent when the premium was collected but the policy could not be issued, finally. On the order, the policy becomes FAILED_FINAL and the refund REQUIRED. errorCode shows why the policy could not be issued.
When you receive the event, read the order from the order endpoint:
- If
refundStatusisPENDINGorREFUNDED, the refund has started;insurance.refund.completedis sent when it completes. - If
refundStatusisREQUIRED, refund the premium with the premium refund endpoint. If you collected the premium outside Lunixi, make the refund through your own channel and report it with the same endpoint.
The premium refund request can be repeated: if the refund has already started, the order is returned as is.
insurance.policy.document_ready
Sent when the documents of the order's issued policies are verified with the provider. data.documentStatus becomes AVAILABLE.
Download the document from data.policies[].documentUrl. This address is the Policy Document endpoint; you sign the request with your API key like your other API requests. The address does not carry any authorization by itself, and the document is not stored at Lunixi.
insurance.policy.cancelled
Sent when the provider finalizes the cancellation of all policies of the order. data.policyStatus becomes CANCELLED. The document of a cancelled policy cannot be retrieved; documentUrl is an empty string.
Cancelling the policy does not refund the premium. The premium refund is a separate step, and insurance.refund.completed is sent when it completes. See Cancellation and Premium Refund.
insurance.refund.completed
Sent when the premium refund is completed. data.refundStatus becomes REFUNDED.
- If the premium was collected in a Lunixi payment, the event is sent when the refund is made from the payment.
- If you collected the premium outside Lunixi, the event is sent when you report the refund with the premium refund endpoint.
insurance.claim.submitted
Sent when a claim reaches the provider and the provider records it. The claim is in data.claim; data.claim.status becomes SUBMITTED. You can get the provider's claim document from the claim document endpoint.
The event does not carry the assessment result of the claim; the assessment is done by the insurance company.
insurance.claim.failed
Sent when a claim is not accepted by the provider or does not reach the provider. data.claim.status becomes FAILED; the reason is in data.claim.errorCode:
data.claim.errorCode | Meaning |
|---|---|
insurance.claim.rejected | The provider rejected the claim. |
insurance.provider.unavailable | The claim did not reach the provider. |
If needed, you can file a new claim for the same policy: Claims.
insurance.lead.submitted
Sent when a lead reaches the provider and the provider receives it. The lead is in data.lead; data.lead.status becomes SUBMITTED. Because a lead is not linked to an order, the data of this event does not carry order fields: Lead event payload.
The event does not carry the provider's steps after the lead (contacting the buyer, an offer).
Cases without an event
No event is sent for the following cases. Track them on the order endpoint:
| Case | On the order |
|---|---|
| A quote or an order was created | The order appears in the order list. |
| The provider rejected the cancellation request | The policy stays in force; errorCode: insurance.policy.cancel_failed. |
| The premium refund was rejected | refundStatus: FAILED, refundErrorCode: insurance.refund.rejected. |
| The policy document could not be verified | documentStatus: FAILED. The issued policy stays valid; you can still request the document from the Policy Document endpoint. |
| The outcome of a claim is not final | The claim shows status: UNKNOWN on the claim endpoint. When the outcome is final, insurance.claim.submitted or insurance.claim.failed arrives. |
| The outcome of a lead is not known or the lead failed | The lead shows status: UNKNOWN or FAILED on the lead endpoint. The outcome is also returned in the response to the lead request. |
Delivery structure
The delivery body is an envelope; the order's fields are under data.
Envelope
| Field | Meaning |
|---|---|
id | Event ID; the same value as the x-lunixi-event-id header and data.eventId. |
type | Event type, e.g. insurance.policy.issued. |
organizationId | Your organization. |
productCode | INSURANCE_SERVICE |
environment | TEST or LIVE; the environment of the order's provider connection. See Subscription. |
eventVersion | Event version; 1 today. |
schemaVersion | Version of the data schema; v1 today. |
createdAt | When the event occurred. |
data | The order's fields; see below. |
The envelope may contain fields not in this table; base your code only on the fields documented here.
data
data carries the order state after the transition the event describes. The data of the lead event is different: Lead event payload.
| Field | Type | Description |
|---|---|---|
eventId | string | Event ID; the same as id in the envelope. |
eventType | string | Event type; the same as type in the envelope. |
merchantId | string | Your organization; the same as organizationId in the envelope. |
insuranceOrderId | string | Order ID (inso_…). The same value as orderId on the order endpoint. |
paymentIntentId | string or null | The Lunixi payment the order is bound to. |
merchantOrderId | string or null | Your own order number. |
insuranceType | string | Insurance type, e.g. TICKET_CANCELLATION. See Insurance Types. |
premiumCollectedBy | string | Who collected the premium: MERCHANT when you collect it, PROVIDER when your provider collects it (Provider Collection). |
provider | object | The provider that issued the policy: code, name, logoUrl (string or null) and your connection's ID connectionId. For information. |
status | string | Overall status; derived from the four axes. See Concepts › Overall status. |
collectionStatus | string | Collection axis. |
policyStatus | string | Policy axis. |
refundStatus | string | Refund axis. |
documentStatus | string | Document axis. |
premiumAmount | integer | Premium, in minor units (kuruş). |
currency | string | Currency, ISO 4217. |
policies | array | Policies per basket item; fields below. An empty array if no policy was created. |
errorCode | string or null | Present only in insurance.policy.failed and insurance.refund.required: the Lunixi code of the error. Meaning of the codes: Error Codes. |
claim | object | Present only in insurance.claim.* events: the claim the event is about; fields below. |
createdAt | string | When the order was created. The time of the event is createdAt in the envelope. |
Values of the status axes: Concepts › Order statuses.
policies[]:
| Field | Type | Description |
|---|---|---|
policyId | string | Policy ID (insp_…). |
basketItemId | string | The basket item the policy insures. |
policyNumber | string or null | The number on the policy document. null until the policy is issued. |
policyStatus | string | Status of this policy. |
documentStatus | string | Document status of this policy. |
documentUrl | string | If the policy is in force (ISSUED or CANCEL_PENDING), the full address of the Policy Document endpoint; otherwise an empty string. |
claim (only in insurance.claim.* events):
| Field | Type | Description |
|---|---|---|
claimId | string | Claim ID (insclm_…). |
policyId | string | The policy the claim was filed for (insp_…). |
status | string | Status of the claim: SUBMITTED or FAILED. |
incidentAt | string | Time of the incident the claim is about, ISO 8601. |
documentKinds | string[] | Types of the documents sent with the claim. |
errorCode | string or null | Set only in the insurance.claim.failed event: the Lunixi code of the reason. |
submittedAt | string or null | The time it was confirmed that the provider recorded the claim. |
createdAt | string | When the claim was created. |
In claim events, the order's other fields carry the order's status at the time of the event. The document and the provider's claim reference are not included in the payload.
Lead event payload
The data of the insurance.lead.submitted event carries only these fields:
| Field | Type | Description |
|---|---|---|
eventId | string | Event ID; the same as id in the envelope. |
eventType | string | Event type: insurance.lead.submitted. |
merchantId | string | Your organization; the same as organizationId in the envelope. |
lead | object | The lead the event is about; fields below. |
createdAt | string | When the lead was created. The time of the event is the envelope's createdAt. |
lead:
| Field | Type | Description |
|---|---|---|
leadId | string | The lead ID (insl_…). |
insuranceType | string | The lead type, e.g. CARGO_TRANSIT. |
schemaVersion | integer | The version of the lead schema the lead was validated against. |
status | string | The lead status: SUBMITTED. |
submittedAt | string | When the provider received the lead. |
createdAt | string | When the lead was created. |
The lead body, the note and personal data, the provider's name and the lead reference are not included in the payload. Use the retrieve endpoint for the lead's masked view.
In webhooks, fields without a value come as null; the field is still present in the body. Personal data and the provider's own references are not included in the payload.
Subscription
To receive the events, create a webhook endpoint for the insurance product:
| Field | Value |
|---|---|
productCode | INSURANCE_SERVICE |
eventTypes | The events you want, e.g. ["insurance.policy.issued", "insurance.refund.required"]; ["insurance.*"] for all insurance events |
environment | A TEST endpoint receives the events of orders whose provider connection is in the Test environment; a LIVE endpoint those whose connection is in the Live environment. |
curl -X POST "https://api-gateway.lunixi.com/api/v1/organizations/$ORG_ID/webhook-endpoints" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Insurance events — test",
"url": "https://merchant.example.com/webhooks/lunixi",
"productCode": "INSURANCE_SERVICE",
"environment": "TEST",
"secretRef": "vault:<secretId>",
"eventTypes": ["insurance.*"]
}'The event's environment is set by the order's provider connection, not by your API key. When testing, check your connection's environment: Testing › What decides the environment.
Creating the endpoint, the signing secret and delivery history: Webhook Setup.
Signature, retries and deduplication
Verify the signature on every delivery; the signature format and retry policy are the same for all products: Webhooks.
- Delivery is at least once. The same event may arrive more than once. Process the event idempotently by
x-lunixi-event-id. The same event carries the same ID on every delivery; this value is also the same asdata.eventId. - Do not rely on the order. A retried delivery may arrive after a later event. Derive the order's latest state from the status axes in
data, not from the order of events. When in doubt, read the order from the order endpoint. - Respond to the event quickly. Verify the signature, write the event to your own queue and return
2xx. Do work such as downloading the document after the response.
Using the webhook with the order endpoint
The webhook is the fast way to learn the order's outcome; it is not the only source. If your endpoint is unreachable for a while, or the status changed through a path without an event (table above), read the order from the order endpoint. data.insuranceOrderId from the webhook is the same as orderId on the order endpoint.
x-lunixi-event-id and take the latest state from the status axes in data.Related
- Error Codes: meaning of the
errorCodevalues - Concepts and Statuses: status axes and overall status
- Orders and Payment Binding: the order object