Payment Providers

One interface, three gateways

Xendit, Midtrans and Mayar.id sit behind a single PaymentProvider interface, so your integration code barely changes when you switch.

The abstraction

interface PaymentProvider {
  createPayment(applicationId, dto): Promise<PaymentResponse>;
  createPaymentLink(applicationId, dto): Promise<PaymentLinkResponse>;
  savePaymentMethod(applicationId, dto): Promise<SavePaymentMethodResponse>;
  handleCallback(payload): Promise<CallbackResult>;
  verifySignature(payload, signature): boolean;
  verifyCallbackToken(token): boolean;
}

PaymentsService selects the implementation from the provider field. Adding a provider means implementing this interface and registering it in payments.module.ts.

Comparison

FeatureXenditMidtransMayar.id
Bank transfer✅ 8+ banks✅ 8+ banks✅ BNI, BRI, Mandiri, CIMB, Permata, BJB, BSI
E-walletOVO, DANA, LinkAja, ShopeePay, GrabPay, PayMayaGoPay, ShopeePay, DANA, QRISDANA, GoPay, LinkAja, ShopeePay, Jenius
Cards✅✅ advancedVia checkout page
QRIS✅✅✅
Retail outlets—Indomaret, AlfamartAlfamart
Save payment method✅✅❌
Subscriptions✅✅Not via this API
Callback verificationx-callback-tokenSHA256 signatureOptional token
Best forBank transfers & QRISCards, wallets & OTCInvoices & simple links

Xendit

Env: XENDIT_API_KEY, XENDIT_WEBHOOK_TOKEN.

Create a payment with xenditPaymentMethod. Callbacks verify the x-callback-token header.

Midtrans

Env: MIDTRANS_SERVER_KEY, MIDTRANS_CLIENT_KEY.

Callbacks verify SHA256(order_id + status_code + gross_amount + server_key).

Mayar.id

Env: MAYAR_API_KEY, MAYAR_WEBHOOK_TOKEN, optional MAYAR_API_BASE.

Mayar is invoice-based: every payment returns a checkout link. Read the full Mayar.id guide.

Choosing a provider