Skip to main content

Overview

The Payment Module manages all payment-related operations including payment collection creation, payment session handling, payment capture, and refunds. It provides a provider-agnostic interface that works with various payment providers like Stripe, PayPal, and others. Key Features:
  • Payment collection management
  • Payment session handling (authorize, capture)
  • Multi-provider support (Stripe, PayPal, etc.)
  • Payment capture and refund processing
  • Webhook handling for async payments
  • Account holder management
  • Payment method tracking

When to Use

Use the Payment Module when you need to:
  • Process customer payments during checkout
  • Authorize payments before capturing
  • Capture authorized payments
  • Process full or partial refunds
  • Handle payment provider webhooks
  • Store customer payment methods
  • Track payment transactions
  • Support multiple payment providers

Data Models

PaymentCollection

Groups payment sessions for a cart or order.
id
string
required
Unique payment collection identifier
currency_code
string
required
Three-letter ISO currency code
amount
BigNumber
required
Total amount to be paid
authorized_amount
BigNumber
Amount currently authorized
captured_amount
BigNumber
Amount successfully captured
refunded_amount
BigNumber
Amount refunded to customer
status
PaymentCollectionStatus
required
Status: not_paid, awaiting, authorized, partially_authorized, canceled
payment_sessions
PaymentSession[]
Payment sessions in this collection
payments
Payment[]
Completed payments
region_id
string
Associated region ID

PaymentSession

Represents an active payment attempt.
id
string
required
Unique payment session identifier
payment_collection_id
string
required
ID of the parent payment collection
provider_id
string
required
Payment provider identifier (e.g., “stripe”, “paypal”)
currency_code
string
required
Three-letter ISO currency code
amount
BigNumber
required
Payment amount
status
PaymentSessionStatus
required
Status: pending, authorized, error, canceled
authorized_at
DateTime
When payment was authorized
data
object
Provider-specific data (e.g., Stripe payment intent)
context
object
Additional context data

Payment

Represents a completed payment.
id
string
required
Unique payment identifier
payment_collection_id
string
required
ID of the payment collection
payment_session_id
string
ID of the originating payment session
provider_id
string
required
Payment provider identifier
currency_code
string
required
Three-letter ISO currency code
amount
BigNumber
required
Payment amount
captured_at
DateTime
When payment was captured
captures
Capture[]
Payment captures
refunds
Refund[]
Payment refunds

Capture

Represents a payment capture (full or partial).
id
string
required
Unique capture identifier
payment_id
string
required
ID of the payment being captured
amount
BigNumber
required
Captured amount
created_by
string
User ID who initiated the capture

Refund

Represents a payment refund.
id
string
required
Unique refund identifier
payment_id
string
required
ID of the payment being refunded
amount
BigNumber
required
Refund amount
reason_id
string
ID of the refund reason
note
string
Refund note or explanation
created_by
string
User ID who initiated the refund

AccountHolder

Stores customer payment account information.
id
string
required
Unique account holder identifier
email
string
Account holder email
customer_id
string
Associated customer ID
provider_id
string
required
Payment provider identifier
provider_account_id
string
Provider-specific account ID

Service Interface

The Payment Module service is available at @medusajs/medusa/payment.

Create Payment Collection

Create a payment collection for a cart or order.
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"

export async function POST(
  req: MedusaRequest,
  res: MedusaResponse
) {
  const paymentModuleService: IPaymentModuleService = req.scope.resolve(
    Modules.PAYMENT
  )

  const paymentCollection = await paymentModuleService.createPaymentCollections({
    region_id: "reg_us",
    currency_code: "usd",
    amount: 5000,
  })

  res.json({ payment_collection: paymentCollection })
}
data
CreatePaymentCollectionDTO
required
Payment collection data
currency_code
string
required
Three-letter ISO currency code
amount
number
required
Total amount to collect
region_id
string
ID of the associated region
paymentCollection
PaymentCollectionDTO
The created payment collection

Create Payment Session

Initiate a payment session with a provider.
const paymentSession = await paymentModuleService.createPaymentSession(
  "paycol_123",
  {
    provider_id: "stripe",
    currency_code: "usd",
    amount: 5000,
    data: {
      // Provider-specific data
    },
    context: {
      customer_id: "cus_123",
      email: "[email protected]",
    },
  }
)
paymentCollectionId
string
required
ID of the payment collection
data
CreatePaymentSessionDTO
required
Payment session data
provider_id
string
required
Payment provider ID (e.g., “stripe”, “paypal”)
currency_code
string
required
Currency code
amount
number
required
Payment amount
data
object
Provider-specific initialization data
context
object
Additional context (customer info, etc.)
paymentSession
PaymentSessionDTO
The created payment session

Authorize Payment Session

Authorize a payment (reserve funds).
const payment = await paymentModuleService.authorizePaymentSession(
  "paysess_123",
  {
    // Provider-specific authorization data
  }
)
paymentSessionId
string
required
ID of the payment session to authorize
context
object
Provider-specific authorization context
payment
PaymentDTO
The authorized payment

Capture Payment

Capture an authorized payment.
const capture = await paymentModuleService.capturePayment({
  payment_id: "pay_123",
  amount: 5000,
  created_by: "user_admin",
})
data
CreateCaptureDTO
required
Capture data
payment_id
string
required
ID of the payment to capture
amount
number
Amount to capture (defaults to full payment amount)
created_by
string
User ID initiating the capture
capture
CaptureDTO
The created capture

Refund Payment

Refund a captured payment.
const refund = await paymentModuleService.refundPayment({
  payment_id: "pay_123",
  amount: 5000,
  reason_id: "reason_defective",
  note: "Product was damaged",
  created_by: "user_admin",
})
data
CreateRefundDTO
required
Refund data
payment_id
string
required
ID of the payment to refund
amount
number
Amount to refund (defaults to full payment amount)
reason_id
string
ID of the refund reason
note
string
Refund note or explanation
created_by
string
User ID initiating the refund
refund
RefundDTO
The created refund

Handle Provider Webhook

Process payment provider webhooks.
const result = await paymentModuleService.processWebhook({
  provider: "stripe",
  payload: req.body,
  rawData: rawBody,
  headers: req.headers,
})

if (result.action === "authorized") {
  // Handle authorization
} else if (result.action === "captured") {
  // Handle capture
}
data
ProviderWebhookPayload
required
Webhook data
provider
string
required
Payment provider ID
payload
object
required
Webhook payload from provider
rawData
string | Buffer
Raw webhook body (for signature verification)
headers
object
Webhook request headers
result
WebhookActionResult
Webhook processing result with action type

Create Account Holder

Store customer payment account information.
const accountHolder = await paymentModuleService.createAccountHolder({
  email: "[email protected]",
  customer_id: "cus_123",
  provider_id: "stripe",
  provider_account_id: "cus_stripe123",
})

List Payment Providers

Retrieve available payment providers.
const providers = await paymentModuleService.listPaymentProviders()

Integration Examples

With Cart Module

Create payment collection for cart checkout.
import { Modules } from "@medusajs/framework/utils"

const cartModule = container.resolve(Modules.CART)
const paymentModule = container.resolve(Modules.PAYMENT)

// Retrieve cart with totals
const cart = await cartModule.retrieveCart("cart_123", {
  select: ["total", "currency_code"],
})

// Create payment collection
const paymentCollection = await paymentModule.createPaymentCollections({
  currency_code: cart.currency_code,
  amount: cart.total,
})

// Create payment session
const paymentSession = await paymentModule.createPaymentSession(
  paymentCollection.id,
  {
    provider_id: "stripe",
    currency_code: cart.currency_code,
    amount: cart.total,
    context: {
      customer_id: cart.customer_id,
      email: cart.email,
    },
  }
)

With Order Module

Track order payments.
import { Modules } from "@medusajs/framework/utils"

const orderModule = container.resolve(Modules.ORDER)
const paymentModule = container.resolve(Modules.PAYMENT)

// Authorize payment
const payment = await paymentModule.authorizePaymentSession("paysess_123")

// Create order if payment successful
if (payment.captured_at) {
  const order = await orderModule.createOrders({
    // ... order data
  })
  
  // Link payment to order via workflows
}

With Region Module

Region-based payment provider availability.
import { Modules } from "@medusajs/framework/utils"

const regionModule = container.resolve(Modules.REGION)

// Retrieve region with payment providers
const region = await regionModule.retrieveRegion("reg_us", {
  relations: ["payment_providers"],
})

// Get available payment providers for region
const availableProviders = region.payment_providers

Payment Providers

Medusa supports multiple payment providers through a provider pattern:

Stripe

npm install @medusajs/medusa-payment-stripe

PayPal

npm install medusa-payment-paypal

Best Practices

  1. Authorization vs Capture: Use two-step authorization and capture for orders that require fulfillment before charging. Authorize during checkout, capture upon shipment.
  2. Currency Precision: The module automatically rounds amounts to currency-specific precision using Intl.NumberFormat.
  3. Partial Operations: Support partial captures and refunds by specifying amounts less than the total payment amount.
  4. Webhook Security: Always verify webhook signatures using the raw request body. Providers include signature verification in their SDKs.
  5. Error Handling: Payment sessions can fail due to insufficient funds, declined cards, etc. Handle PaymentSessionStatus.ERROR appropriately.
  6. Idempotency: Payment operations should be idempotent to prevent duplicate charges during retries.

Build docs developers (and LLMs) love