Provider Collection
If your agreement with your provider has the provider collect the premium, the premium is not added to your payment. The premium is charged by your provider, separately from your payment. You start the charge with POST /api/v1/insurance/orders/{orderId}/pay.
- Your payment is taken first. If you bound the order to a Lunixi payment, the premium can be charged only after that payment is captured. If your payment was not taken, no payment is sent to the provider.
- The premium is a separate charge. The buyer sees two separate charges: your payment and the provider's premium charge. A failed premium charge does not affect your payment.
- The premium does not go through your Lunixi payment. It is not part of your payment record or your payout; it is paid directly to the provider.
- The policy is requested automatically once the premium is charged. You do not call
issue-policy.
This is available on the API path only. The Checkout Form offers only the products whose premium you collect.
Before you start
- In the panel, on the POS Center > Insurance page, set Who collects the premium to Provider collects for the product in your connection: Provider Connection › Products on this connection. The list shows only the methods the product supports.
- For this product,
premiumCollectedByisPROVIDERon quote options and orders. - The provider's product charges the premium in one of two ways:
| Method | paymentInput | What you send |
|---|---|---|
| By card | CARD | The buyer's card details. Only PCI-DSS certified merchants may send them; see Card details. |
| On the provider's payment page | HOSTED | No card. You redirect the buyer with nextAction; see Buyer action. |
Flow
… stands for /api/v1/insurance. The premium never goes through your payment; if it cannot be charged, your payment stays valid. You do not call issue-policy.Get a quote and create an order
The quote and order steps are the same as in the other flows: Quotes, Orders. Continue before the option expires; charging the premium requires a valid option.
Take your payment
- If you take the payment with Lunixi, create the payment with the insurance-enabled items and bind the order to it with
bind-payment: Binding to a payment. The basket has no premium item; the premium is not added to your payment. The payment must be a direct sale (no pre-authorization). - If you take the payment outside Lunixi, you do not bind the order to a payment.
confirm-paymentis not used for these orders.
Charge the premium
Call /pay after your Lunixi payment is captured (or after you took your own payment). If the product charges a card, send the buyer's card details in the body.
Handle the outcome
Continue according to providerPayment.status in the response: Outcomes. If the outcome is ACTION_REQUIRED, redirect the buyer to nextAction.redirectUrl.
Track the policy
Once the premium is charged, the policy is requested automatically. Track the result on the order endpoint or with webhooks.
Charging the premium: POST /api/v1/insurance/orders/{orderId}/pay
Authentication
Because this endpoint can carry card data, it applies the same identity rule as the direct payment endpoints: a Bearer access token together with an Ed25519 request signature (Step-Up). Unlike the other insurance endpoints, the Authorization header is required.
| Header | Value |
|---|---|
Authorization | Bearer <access token> |
X-Key-Id, X-Date, X-Nonce, Digest, X-Signature | Signature headers; the rules are the same as in Flows › Authentication. |
Idempotency-Key | Required. 8-200 printable ASCII characters, no spaces. |
Getting an access token and the Step-Up rules: Authentication. The token and the signing key must belong to the same account and the same environment.
Request
| Path parameter | Description |
|---|---|
orderId | Order ID (inso_…). |
| Field | Type | Required | Description |
|---|---|---|---|
card | object | Yes for CARD products | The buyer's card details; fields below. Not sent for HOSTED products. |
returnUrl | string | No | Your page the buyer returns to after the provider's page. https only; no user info and no # fragment; at most 2048 characters. See Return. |
source lunixi-sign.sh
REQ_PATH="/api/v1/insurance/orders/<orderId>/pay"
BODY='{"card":{"cardNumber":"<card number>","expireMonth":"<MM>","expireYear":"<YYYY>","cvcNumber":"<security code>","cardHolderName":"<card holder>"},"returnUrl":"https://example.com/insurance/return"}'
lunixi_sign POST "$REQ_PATH" "$BODY"
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
-H "Authorization: Bearer $LUNIXI_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: insurance-pay-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"If the product charges on the provider's payment page (HOSTED), the body carries only returnUrl.
Card details
Only PCI-DSS certified merchants may send raw card data. Receiving, storing or transmitting the card number and security code on your server brings your systems into PCI DSS scope. If you are not certified, do not send cards to this endpoint. See PCI DSS.
| Field | Type | Description |
|---|---|---|
card.cardNumber | string | Card number; 12-19 digits, no spaces. |
card.expireMonth | string | Expiry month; two digits (01-12). |
card.expireYear | string | Expiry year; two or four digits. |
card.cvcNumber | string | Security code; 3 digits (4 for AMEX). |
card.cardHolderName | string | First and last name as on the card; at most 100 characters. |
- If your account is not registered as PCI-DSS certified, a request to a card product returns
403 insurance.card.pci_requiredbefore the card is processed; no request is sent to the provider. - The card is not stored by Lunixi. It is processed only during the request and forwarded to your provider. The security code is not kept anywhere.
- Card details never appear in responses, error messages, request logs or webhooks. An error response only says which field is invalid.
- If the card format is invalid (for example, the card number fails validation or the card has expired), the request returns
422 insurance.card.invalid; the invalid field is indetails.field. No request is sent to the provider.
Response
When the request completes it returns 200. data carries two objects:
| Field | Description |
|---|---|
order | The current state of the order: Order object. |
providerPayment | The premium charge attempt; fields below. |
providerPayment:
| Field | Type | Description |
|---|---|---|
insurancePaymentId | string | Charge attempt ID (inspay_…). |
orderId | string | Order ID (inso_…). |
status | string | The outcome of the attempt; see Outcomes. |
paymentInput | string | How the premium is charged: CARD or HOSTED. |
amount | integer | The premium charged, in minor units. |
currency | string | Currency, ISO 4217. |
failureCode | string or null | The Lunixi error code if the attempt failed, e.g. insurance.payment.declined. |
nextAction | object or null | The step the buyer must take; see Buyer action. |
createdAt | string | When the attempt was created, ISO 8601. |
updatedAt | string | When it last changed, ISO 8601. |
The response does not include the provider's references, payment page address or error codes. Card details are never included in any form.
Outcomes
providerPayment.status | On the order | What to do |
|---|---|---|
SUCCEEDED | Collection COLLECTED, policy PENDING | The premium was charged. The policy is requested automatically; you receive the result with insurance.policy.issued. |
ACTION_REQUIRED | Collection ACTION_REQUIRED; order.nextAction is set | Redirect the buyer to nextAction.redirectUrl: Buyer action. |
FAILED | Collection FAILED, errorCode insurance.payment.declined | The provider declined the charge. Your payment stays valid. insurance.policy.failed is sent. If the buyer wants to try another card, call again with a new Idempotency-Key. |
UNKNOWN | Collection UNKNOWN | The outcome of the charge is not final yet. The charge is not repeated; the order stays in this state until the outcome is confirmed. Do not charge the buyer again and do not start a new attempt. |
PENDING | Collection PENDING | The attempt is in progress. You see this value only when you repeat a request with the same Idempotency-Key; track the order on the order endpoint. |
- An order has at most one open attempt at a time. While an open (
PENDING,ACTION_REQUIRED,UNKNOWN) or successful attempt exists, no new attempt can be started; the same card is never charged twice. - If the request fails before reaching the provider (e.g. the provider cannot be reached), no money moves: an error response is returned and the order goes back to its previous collection state. You can repeat the request after a while.
Retries and Idempotency-Key
- Charging the premium sends the offer to the provider and performs the charge in the same request. The request can take more than a minute; set your client timeout accordingly.
- After a timeout or a
5xx, repeat the request with the sameIdempotency-Keyand the same body. The same key returns the same attempt; the card is not processed again and no second charge is made. - Generate a new key for a new attempt (e.g. another card after a declined charge).
Buyer action (nextAction)
If the provider needs the buyer to take a step for the charge (3-D Secure verification or the provider's payment page), the attempt becomes ACTION_REQUIRED and nextAction is returned. The same object is also on the order's nextAction field while the step is pending.
| Field | Type | Description |
|---|---|---|
type | string | REDIRECT |
redirectUrl | string | The Lunixi address you redirect the buyer's browser to. |
expiresAt | string or null | The deadline for the step, ISO 8601. |
redirectUrlis a Lunixi address (/api/v1/insurance/payments/{insurancePaymentId}/redirect). Lunixi redirects the buyer from there to the provider's page; the provider's page address is not shared with you.- Open the address only in the buyer's browser. Once the return is processed, or when the attempt is no longer waiting for the buyer, the address returns
404 insurance.payment.not_found. - If the buyer does not return by
expiresAt, the outcome is confirmed with the provider.
Return
When the buyer completes the step on the provider's page, the provider returns to Lunixi. Then:
- If you sent
returnUrl, the buyer is redirected to it with these query parameters added:insurancePaymentId,orderId,status. - If you did not send
returnUrl, the result is shown to the buyer as JSON. SendreturnUrlon every request where you redirect the buyer.
The return alone is not proof of payment. Use the status query parameter only to choose what to show the buyer; confirm that the premium was charged and the policy issued on the order endpoint or with webhooks.
Errors
| HTTP | code | What to do |
|---|---|---|
400 | VALIDATION_ERROR | Fix the format; this error is also returned when Idempotency-Key is missing. |
401 | Authentication codes | Check the Bearer token and the signature headers: Authentication. |
403 | AUTH_MERCHANT_MISMATCH, AUTH_ENVIRONMENT_MISMATCH | The token and the signing key must belong to the same account and the same environment. |
403 | PRODUCT_NOT_ENABLED | The insurance product is not enabled on your account or key. |
403 | insurance.card.pci_required | The product charges by card, but your account is not registered as PCI-DSS certified. The card is not processed and no request is sent to the provider. |
404 | insurance.order.not_found | The order was not found or belongs to another account. |
409 | insurance.order.state_conflict | See details.reason; table below. |
409 | insurance.quote.expired | The option expired; get a new quote and create a new order. |
412 | insurance.payment.merchant_payment_not_captured | The Lunixi payment bound to the order is not captured yet. Retry after the payment is captured. |
422 | insurance.payment.method_not_supported | Provider collection cannot be used for this order; see details.reason, table below. |
422 | insurance.card.invalid | The card details are invalid; fix the field in details.field. |
422 | insurance.validation.invalid | Fix the fields in details.errors[]. For example, card was not sent for a CARD product (field: card, reason: required) or returnUrl is invalid (reason: https_required or invalid). |
422 | insurance.reference.unknown | A reference code on the order has no counterpart at this provider; no request is sent to the provider. |
422 | insurance.quote.declined | The provider did not accept the offer on the same terms; get a new quote. |
503 | insurance.provider.unavailable | The provider could not be reached; no money moved. Retry after a while. |
Common codes: Flows › Responses and errors.
State conflict
reason | Meaning |
|---|---|
not_provider_collection | You collect the premium of this order (premiumCollectedBy: MERCHANT). Collect it as described in Premium and Payment. |
provider_payment_in_progress | The order has an open attempt: in progress, waiting for the buyer, or with an outcome that is not final. |
premium_collected | The premium has already been charged. |
offer_outcome_unknown | The outcome of sending the offer to the provider is not final; the premium is not charged. The order is reviewed. |
Unsupported collection
reason | Meaning |
|---|---|
card_path_not_enabled | Provider collection by card is not available in this environment. |
card_not_accepted | The product charges the premium on the provider's payment page (HOSTED); do not send card. |
preauth_payment | The payment bound to the order is a pre-authorization. Provider collection is used only with direct sale payments. |
provider_payment_not_supported | This product or provider does not collect the premium with a provider charge. |
Cancellation and refund
- You can cancel the policy with the
cancelendpoint: Cancellation and Premium Refund › Policy cancellation. - Because the premium is paid to the provider, it is not refunded through Lunixi;
refund-premiumreturns409(reason: collected_by_provider) for these orders. - Refunds you make from your own payment are not linked to insurance and do not cancel the policy.
Related
- Orders and Payment Binding: the order object and
bind-payment - Premium and Payment: flows where you collect the premium
- Insurance-Only Integration: the end-to-end flow without a Lunixi payment
- Webhook Events:
insurance.policy.issuedandinsurance.policy.failed - Error Codes: provider collection codes