Payment Orchestrator
Marketplace
2D Payment

Split 2D Payment

A split payment is a normal payment plus sellers[] — you declare which sub-dealer gets how much of the charge, and Lunixi enforces seller eligibility, computes commission, hold and net per seller leg, and records the full breakdown on the transaction. Use the 2D route when the transaction will not run a 3DS challenge; for the challenge flow see Split 3D Secure Payment.

⚠️

All amounts are minor units (kuruş): "amount": 25000 = ₺250.00. Note the asymmetry: the top-level amount is an integer, while each seller leg's amountMinor is a string ("15000").

How it works

Eligibility gate

Before any money moves, every seller in sellers[] is checked: is the seller ACTIVE, KYC-complete and payout-configured? Ineligible sellers are rejected according to your multiSellerPolicy.

Split & commission

The gross is split across seller legs; the commission rules you defined resolve each leg's commission, hold and net.

Charge

The card is charged through the core payment pipeline — same routing, failover and idempotency as a regular payment.

Record

Commission, hold and net per seller are written to the transaction record — inspect them any time via GET /marketplace/transactions.

Two ways to take a split payment

Hosted checkout formDirect API (2D)
Card dataCollected on Lunixi's form — never touches your serverSent server-to-server (you are in PCI DSS scope)
You callPOST /payments/marketplace/intents → form flowPOST /payments/marketplace/2d
Split declaredAt intent creationOn the charge request

Hosted form route

POST /payments/marketplace/intents accepts everything a core checkout form intent accepts, plus sellers[] and multiSellerPolicy. The seller legs must add up to the intent's amount (see below). Eligibility is gated and the split computed at intent creation; the buyer then completes the standard hosted form flow, and the charge applies the split. Everything after intent creation — tokenize, BIN/installments, 2D/3D submit — is identical to the core flow, so follow the Checkout Form guide from step 2 onward.

Direct API route

POST /payments/marketplace/2d is a Step-Up endpoint: Bearer token plus Ed25519 request signature, like every money-movement call.

⚠️

The direct route carries raw PAN. Only use it if your integration is PCI DSS certified — otherwise use the hosted form route above.

Request

curl -X POST https://api-gateway.lunixi.com/api/v1/payments/marketplace/2d \
  -H "Authorization: Bearer <access-token>" \
  -H "X-Key-Id: <key-id>" \
  -H "X-Date: <iso-timestamp>" \
  -H "X-Nonce: <nonce>" \
  -H "X-Signature: <ed25519-signature>" \
  -H "Idempotency-Key: 5c1e6a3e-90bd-4b2f-a1c7-1f0d1c9e2ab4" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25000,
    "currency": "TRY",
    "orderId": "ORD-2026-1042",
    "card": {
      "cardNumber": "5400000000000005",
      "expireMonth": "12",
      "expireYear": "27",
      "cvcNumber": "123"
    },
    "sellers": [
      { "subDealerId": "d_8f2a...", "amountMinor": "15000" },
      { "subDealerId": "d_c41b...", "amountMinor": "10000" }
    ],
    "multiSellerPolicy": "ALL_OR_NOTHING"
  }'

The sellers[] array

FieldTypeNotes
subDealerIdstringThe seller's dealer id — must be ACTIVE and payout-configured
amountMinorstringThis seller's share, minor units as a string
scenarioobject, optionalPer-request commission scenario override for this leg

Multiple entries for the same subDealerId (e.g. several basket items from one seller) are aggregated into a single leg.

The sellers' amountMinor values must add up to exactly the request's amount. A lower or higher total is rejected with 400 VALIDATION_ERROR before the card is charged. amountMinor contains digits only ("15000").

multiSellerPolicy

PolicyBehaviour
ALL_OR_NOTHING (default)If any seller is ineligible, the whole payment is rejected with 422 before the card is charged — no partial fulfilment risk
PARTIAL_ALLOWEDIneligible legs are marked REJECTED; the payment proceeds with the eligible sellers

Response

A successful charge returns the standard payment result:

{
  "success": true,
  "intentId": "pay_01HV3K9X7QWE...",
  "status": "CAPTURED",
  "attemptCount": 1,
  "createdAt": 1782115200000
}

The per-seller breakdown — each leg's gross, commission, hold and net — is written to the transaction record rather than inlined here. Read it with GET /marketplace/transactions, where each split payment lists its seller legs.

Errors

StatusMeaningWhat to do
422One or more sellers ineligible (under ALL_OR_NOTHING)Inspect details.ineligible[] — see below
400Validation failed (leg amounts, legs not adding up to amount, missing fields). If a removed amount field was sent: payment.amount.field_removedFix the request body
401 / 403Step-Up auth failed (bad signature, stale X-Date, reused nonce)Re-sign the request — see Authentication

The 422 ineligibility response

{
  "code": "marketplace.payment.seller_not_eligible",
  "message": "One or more sellers are not eligible for marketplace payment.",
  "details": {
    "policy": "ALL_OR_NOTHING",
    "ineligible": [
      { "subDealerId": "d_c41b...", "reasonCode": "SELLER_KYC_REQUIRED" }
    ]
  }
}
reasonCodeMeaningFix
SELLER_SUSPENDEDSeller is suspended, on hold or closedReactivate via PUT /marketplace/dealers/{id}/status if appropriate
SELLER_KYC_REQUIREDOnboarding/KYC not completeHave the seller finish onboarding
SELLER_PAYOUT_NOT_CONFIGUREDNo payout configuration for the seller yetComplete payout terms during onboarding

Webhooks

Split payments emit the same events as core payments — payment.captured, payment.failed, payment.refunded, payment.voided and the rest of the payment.* family. There are no marketplace-specific event types; correlate by orderId / payment id and read the seller breakdown from the transactions endpoint.

Next steps