Skip to main content

Split Order Payment Module

In this section of the documentation, you will find resources to learn more about the Split Order Payment Module and how to use it in your application. Mercur has payment splitting features available out-of-the-box through the Split Order Payment Module. A module is a standalone package that provides features for a single domain. Each of Mercur’s marketplace features are placed in custom modules, such as this Split Order Payment Module. Learn more about why modules are isolated in this documentation.

Split Order Payment Features

  • Payment Tracking per Seller: Track payment amounts (authorized, captured, refunded) separately for each seller’s portion of a multi-vendor order.
  • Payment Collection Association: Link split payments to the main payment collection for the entire cart.
  • Automatic Status Updates: Automatically update split payment status when the main payment is captured.
  • Refund Management: Handle partial refunds specific to each seller’s order.
  • Financial Reconciliation: Maintain accurate payment records for commission calculation and payout processing.

How to Use the Split Order Payment Module

In your Medusa application, you build flows around Commerce Modules. A flow is built as a Workflow, which is a special function composed of a series of steps that guarantees data consistency and reliable roll-back mechanism. You can build custom workflows and steps. Mercur provides pre-built workflows for split payment operations in the @mercurjs/b2c-core package. For example, the markSplitOrderPaymentsAsCapturedWorkflow:
src/workflows/split-order-payment/mark-split-order-payments-as-captured.ts
import {
  WorkflowResponse,
  createWorkflow,
  transform
} from '@medusajs/framework/workflows-sdk'
import { useQueryGraphStep } from '@medusajs/medusa/core-flows'
import { updateSplitOrderPaymentsStep } from '../steps'

export const markSplitOrderPaymentsAsCapturedWorkflow = createWorkflow(
  {
    name: 'mark-split-order-payments-as-captured'
  },
  function (payment_collection_id: string) {
    // Query all split payments for this payment collection
    const payments = useQueryGraphStep({
      entity: 'split_order_payment',
      fields: ['*'],
      filters: {
        payment_collection_id
      }
    })

    // Transform to update payload
    const updatePayload = transform(payments, (payments) => {
      const entities = payments.data
      return entities.map((p) => ({
        id: p.id,
        status: 'captured',
        captured_amount: p.authorized_amount
      }))
    })

    // Update all split payments to captured
    const splitOrderPayments = updateSplitOrderPaymentsStep(updatePayload)
    return new WorkflowResponse(splitOrderPayments)
  }
)
You can then execute the workflow in your custom API routes, scheduled jobs, or subscribers:

Subscriber

src/subscribers/split-payment-payment-captured.ts
import { SubscriberArgs, SubscriberConfig } from '@medusajs/framework'
import { Modules, PaymentEvents } from '@medusajs/framework/utils'
import { markSplitOrderPaymentsAsCapturedWorkflow } from '../workflows/split-order-payment/workflows'

export default async function paymentCapturedHandler({
  event,
  container
}: SubscriberArgs<{ id: string }>) {
  const payment_id = event.data.id
  const paymentService = container.resolve(Modules.PAYMENT)

  // Retrieve payment with its collection
  const payment = await paymentService.retrievePayment(payment_id, {
    relations: ['payment_collection']
  })

  // Mark all split payments as captured
  await markSplitOrderPaymentsAsCapturedWorkflow.run({
    container,
    input: payment.payment_collection_id
  })
}

export const config: SubscriberConfig = {
  event: PaymentEvents.CAPTURED,
  context: {
    subscriberId: 'split-payment-payment-captured-handler'
  }
}
Learn more about workflows in this documentation.

Concepts

In this document, you’ll learn about the main concepts related to split order payments in Mercur.

Split Order Payment

A split order payment tracks the payment amounts specific to an individual seller’s order within a multi-vendor purchase. It is represented by the SplitOrderPayment data model. A split order payment holds information about:
  • Payment status (authorized, captured, refunded)
  • Authorized amount for this seller’s portion
  • Captured amount (funds actually received)
  • Refunded amount (funds returned to customer)
  • Currency code
  • Associated payment collection ID
This allows the marketplace to track payment lifecycle events separately for each vendor involved in a multi-vendor order.

Why Split Order Payments?

In a multi-vendor marketplace, when a customer checks out with products from multiple sellers: Payment Flow:
  1. Customer authorizes payment for the total cart amount ($100)
  2. Cart splits into 3 orders: Seller A (40),SellerB(40), Seller B (35), Seller C ($25)
  3. Three SplitOrderPayment records are created, tracking each seller’s portion
  4. Payment is captured ($100 total)
  5. Each split payment updates to “captured” with their respective amounts
  6. Commission is calculated per split payment
  7. Payouts are processed to each seller (minus commission)
Without Split Payments:
  • No way to track which seller’s portion was captured/refunded
  • Commission calculation would be difficult
  • Payout processing would require complex lookups
  • Refund handling would be ambiguous
With Split Payments:
  • Clear payment tracking per seller
  • Simple commission calculation
  • Straightforward payout processing
  • Accurate refund attribution

Payment Lifecycle

1. Authorization

When a cart is completed:
  • Main payment collection is created for the total amount
  • Individual orders are created per seller
  • SplitOrderPayment records are created with status authorized
  • authorized_amount is set to each seller’s order total

2. Capture

When payment is captured (either immediately or later):
  • Main payment’s payment.captured event is emitted
  • Subscriber triggers markSplitOrderPaymentsAsCapturedWorkflow
  • All split payments for the payment collection are updated:
    • statuscaptured
    • captured_amountauthorized_amount

3. Refund

When a refund is processed:
  • Refund workflow identifies the specific seller’s order
  • SplitOrderPayment is updated:
    • refunded_amount is incremented
    • If fully refunded and refunded_amount equals captured_amount
This lifecycle tracking enables accurate financial reconciliation across the marketplace.

Integration with Payment Module

Split order payments are tightly integrated with Medusa’s Payment Module:
  • PaymentCollection: The parent payment collection for the entire cart
  • Link: One-to-one link between Order and SplitOrderPayment
  • Event-Driven: Listens to PaymentEvents.CAPTURED to update split payment status
  • Automatic Sync: Split payments stay synchronized with main payment lifecycle
This architecture separates concerns:
  • Payment Module: Handles actual payment processing with providers
  • Split Order Payment Module: Tracks seller-specific payment amounts
  • Payout Module: Uses split payment data for seller payouts

Status Values

Split order payments use string-based status tracking:
  • authorized: Payment has been authorized but not yet captured
  • captured: Payment has been captured and funds are secured
  • refunded: Payment has been fully refunded to the customer
  • partially_refunded: Some but not all funds have been refunded
The status field is flexible to accommodate provider-specific statuses or custom payment flows.

Use Cases

1. Multi-Vendor Checkout Customer purchases from 3 sellers; system creates 3 split payments tracking each seller’s payment portion. 2. Delayed Capture Marketplace authorizes payment on checkout but captures later (e.g., after shipping). Split payments track both authorization and capture timing. 3. Partial Refunds Customer returns items from one seller; that seller’s split payment tracks the refunded amount separately. 4. Commission Calculation Commission module uses captured_amount from split payments to calculate marketplace fees per seller. 5. Payout Processing Payout job queries orders with captured split payments to determine which sellers should receive funds. 6. Financial Reporting Generate reports on authorized vs captured amounts per seller for cash flow analysis.