• Модуль интеграций
  • Сообщество
  • Блог
Документация
Плагины и интеграцииВсе расширения для Medusa от сообществаСтартерыЗапускайте проекты быстрее с готовыми решениями
ЭкспертыПодберите специалиста для разработки и развития вашего проекта на MedusaКейсыПосмотрите примеры Medusa в продакшене и успешные внедрения
Представляем готовый к продакшену Medusa DTC Starter от Gorgo

26 августа 2026 г. · Продукт

Gorgo снижает затраты на адаптацию Medusa к локальным рынкам.

Мы разрабатываем плагины интеграции, осуществляем поддержку и развиваем сообщество разработчиков на Medusa в Telegram.

  • Ресурсы Medusa
  • Плагины и интеграции
  • Модуль интеграций
  • Стартеры
  • Эксперты
  • Кейсы
  • Medusa Чат в Telegram
  • Medusa Новости в Telegram
  • Документация Gorgo
  • Связаться с нами
  • TelegramGitHub
Плагины
O

Openborder

Платёжный и налоговый провайдер Medusa для Open Border.

npm install @open-border/medusa-payment-openborder
Категория
Платежи
Создано
Open-border
Версия
0.9.7
Последнее обновление
2 недели назад
Ежемесячные загрузки
Загрузка данных
Звезды на Github
0
npmNPM

Open Border Medusa payment plugin

Medusa payment and tax provider bridge for Open Border. Medusa owns the storefront, cart, order, and fulfillment flow; Open Border owns Merchant-of-Record tax, duty, payment-intent, entity-routing, and ledger state.

This package is intentionally thin. It stores no authoritative money state and calls the Open Border API through the Node SDK.

Setup instructions are canonical at . That published page is the step-by-step setup guide; this README stays the detailed integration reference for package consumers. When the two disagree about a setup step, the published guide wins — update it in the same change.

Package pages

  • npmjs public package:
  • Browser checkout element:
  • Node SDK:
  • Public demo source:

Upgrading from 0.7.x

A tax quote is now required on every charge. Open Border rejects a payment intent with no as a , so a cart that reaches payment-session creation without a quote id fails closed in the plugin rather than charging an untaxed total. Run the Open Border tax provider on the cart before creating the payment session, and keep the server-issued alongside the quote id.

If your storefront relied on creating a session for an unquoted cart, that path no longer produces a charge — quote first. This narrows the published input contract, so the first release containing it is a breaking minor (), never a patch.

Upgrading from 0.6.x

The unified Medusa major-unit boundary is a breaking change for the sibling money fields. The first release containing it must be a new minor ( or later), never a patch.

In , the provider already treated Medusa's payment as major units, but and were documented and forwarded as Open Border minor units. Starting with , pass all three as Medusa major-unit values:

Field input input
Payment total
Server minor unitsminor units

Update the payment-session and tax-provider inputs atomically before upgrading. Integer major and minor values are ambiguous, so the plugin cannot safely auto-detect a mixed old/new payload. Quoted payment sessions must also retain the server-issued alongside the quote id so the provider can reconcile Medusa's payment total before authorization. Keep that breakdown exactly as returned; its fields remain integer minor units.

Install

Install the public npm packages. No or registry token is required:

Configuration

Configure the Medusa server with an Open Border secret key. Keep this key server-side only.

Key rules:

  • is the key. It belongs on the Medusa server and is used by the plugin to quote tax/duty and create payment intents.
  • is the key. It is safe for browser code and is used by to tokenize the buyer's card into a payment method.
  • Test and live rails do not mix. Use with , and with .
  • is optional outside local development because the SDK can choose the API host from the key rail. Pass it explicitly for local or internal staging environments.

Register the payment provider

Add the Open Border provider to the Medusa v2 Payment Module.

The provider identifier is . With the provider also set to , Medusa stores the resolved provider id as .

Checkout flow

The integration is quote-before-pay:

  1. Build Open Border line items from the Medusa cart.
  2. Quote tax/duty for the buyer's ship-to destination.
  3. Mount the browser checkout element with the quoted landed-cost total.
  4. Send the resulting payment method back to the Medusa server.
  5. Create or update the Medusa payment session with the payment method and quote id.
  6. The Open Border provider creates the payment intent server-side.
  7. Store the Open Border payment intent id and show the buyer the receipt/order ids.

1. Build quote line items

Use Medusa's major-unit values at the plugin boundary (for example, for USD). The plugin converts every amount to Open Border's integer minor-unit contract after exactness checks. Each line item also needs an HS tariff code before the tax quote can be created.

If your catalog does not already store HS codes, classify products with Open Border before quoting and persist the resulting code back to your product/variant metadata.

2. Quote tax and duty

The plugin exposes a thin Open Border client seam for testable Medusa integrations:

US and CA destinations require at least one of or . Forward the Medusa shipping address values as shown; other destinations may omit both.

is the landed-cost total to display before card collection. must travel with the payment session so Open Border can revalidate the quote when creating the payment intent.

3. Collect the payment method in the browser

Use the publishable key with . The browser element only tokenizes the card. It does not charge the buyer and never receives the secret key.

Only expose and, when needed, a non-secret browser API URL. Do not serialize into HTML, JavaScript, logs, analytics, or error telemetry.

4. Create or update the payment session

When the buyer submits the card element, put the Open Border payment method and quote data into the Medusa payment-session data. The provider reads these fields:

Required values:

  • , , or - a persisted Medusa identity that remains stable across retries of the same payment session.
  • or - the token from the browser element.
  • or - the server-issued quote id. Required: Open Border prices every charge from a revalidated quote, so a cart with no quote is refused before any authorization.
  • - the server-issued quote breakdown, retained in minor units so the provider can reconcile Medusa's payment-collection total before authorization.
  • - the same item fingerprint used for the quote.
  • - a Medusa major-unit value, when shipping was included in the quote.
  • and
  • and

Optional values:

  • - usually the Medusa cart, order, or payment collection id. When omitted, the provider uses the required stable session identity.

Provider behavior

The payment provider maps a Medusa-shaped payment-session request into a manual-capture , so Medusa can authorize first and capture or cancel through its later payment lifecycle. Medusa passes money in major units (for example, for USD), so the payment and tax providers exactness-check and convert the payment-collection total, shipping amount, and every line-item unit amount to Open Border minor units. The payment provider derives Open Border's merchandise subtotal from because Medusa's is the full payment-collection total, including shipping and quoted tax or duty. Every payment requires the server-issued ; the provider checks its total, subtotal, shipping, and currency before authorization. The tax provider maps the normalized line items and destination context into , returning the Open Border quote id and aggregate quote response. The plugin does not allocate tax or duty per line locally; Open Border remains the authoritative pricing source.

The Medusa wrapper derives operation-scoped Open Border idempotency keys. Initiate and update use the persisted payment-session identity, prior intent id, and canonical request body; capture and cancel use the persisted Open Border payment-intent id. A changed on a retry does not change those keys. Refunds keep their existing behavior: a stable Medusa refund reference is preferred, with the request context key used only when no refund reference exists. Status lookup reads the current Open Border payment-intent status and does not own local money state. An update cancels a live authorization before creating its replacement, and a canceled intent can be replaced. An update against a captured intent fails closed before cancellation or re-authorization so a completed payment cannot produce a second buyer hold.

If the provider is called before a payment method exists, it returns a pending session with . After the browser returns a token, update the session and the provider will create the Open Border payment intent.

Receipt fields

After a successful payment-intent create, persist the returned Open Border ids alongside the Medusa order/payment collection:

  • - the Open Border entity resolved from charge currency.
  • - subtotal, shipping, tax, duty, total, and currency.
  • , when returned by the payment processor flow.

These fields let support staff reconcile Medusa orders to Open Border transactions without making Medusa the source of truth for money.

Local and staging test mode

Local development:

Sandbox or internal staging:

Use test card numbers from the payment processor account attached to the resolved Open Border entity. The publishable key must belong to the same test rail as the secret key.

Demo preview vs public package guide

The demo source is maintained publicly in . Its deterministic, keyless static build is hosted as a public preview and does not submit a real payment.

This README is the public integration guide for package consumers. Do not document the private demo-only helper routes in Scalar or treat the hosted preview as the required package integration path. External developers should install the package, register the provider, quote tax/duty server-side, collect a browser payment method with the publishable key, and let Open Border create the payment intent with the secret key on the Medusa server.

Current limitations

  • The browser payment element comes from ; this plugin does not render checkout UI by itself.
  • Medusa webhook action handling currently returns . Wire provider webhooks and async reconciliation in a separate integration slice.
  • Capture, cancel, refund, and payment-status lookup delegate to Open Border APIs. Capture and cancel keys are intent-derived; refunds need a stable refund reference or a request context key.
  • The plugin does not allocate tax or duty per line locally. Open Border's quote and transaction snapshot are authoritative.
  • The plugin does not persist Open Border ids into Medusa order metadata for you; do that in your checkout/order completion workflow.
  • , , and are explicit server-side fulfillment seams. Responses keep OpenBorder's fulfillment state separate from nullable advisory Ship24 state in . The is required; is optional and may be omitted for Ship24 auto-detection. also requires because accepted tracking can release held funds. The package does not install an automatic Medusa lifecycle subscriber or guess fulfillment events.

Security checklist

  • Keep keys server-side.
  • Expose only keys to browser code.
  • Use test keys and sandbox URLs until production activation is approved.
  • Send payment-method tokens from the browser to your backend over HTTPS.
  • Never log full API keys, payment method ids, card data, or customer addresses in public logs.
  • Treat Open Border's payment intent, transaction snapshot, and amount breakdown as the authoritative money record.

Еще в этой категории

Посмотреть все
Платежи
Braintree logo

Braintree

От Lambda Curry

Поддержка платежей и 3D Secure через Braintree

Загрузка данных
GitHubnpm
Платежи
Pay. logo

Pay.

От Webbers

Принимайте кредитные карты, цифровые платежи и купи сейчас, плати потом

Загрузка данных
GitHubnpm
Платежи
Mollie logo

Mollie

От Variable Vic

Легко принимайте мультивалютные платежи через Mollie

Загрузка данных
GitHubnpm
npm install @open-border/medusa-payment-openborder @open-border/js
1# Local development
2OPENBORDER_API_URL=http://localhost:3000
3OPENBORDER_API_KEY=sk_test_dev
4OPENBORDER_PUBLISHABLE_KEY=pk_test_dev
5
6# Sandbox / staging
7# OPENBORDER_API_URL=https://api-sandbox.openborderpayments.com
8# OPENBORDER_API_KEY=sk_test_...
9# OPENBORDER_PUBLISHABLE_KEY=pk_test_...
10
11# Production
12# OPENBORDER_API_URL=https://api.openborderpayments.com
13# OPENBORDER_API_KEY=sk_live_...
14# OPENBORDER_PUBLISHABLE_KEY=pk_live_...
1// medusa-config.ts
2module.exports = {
3 modules: [
4 {
5 resolve: '@medusajs/medusa/payment',
6 options: {
7 providers: [
8 {
9 resolve: '@open-border/medusa-payment-openborder/providers/openborder',
10 id: 'openborder',
11 options: {
12 apiKey: process.env.OPENBORDER_API_KEY,
13 baseUrl: process.env.OPENBORDER_API_URL,
14 },
15 },
16 ],
17 },
18 },
19 ],
20};
1const openBorderLineItems = cart.items.map((item) => ({
2 sku: item.variant?.sku,
3 description: item.title,
4 quantity: item.quantity,
5 unit_amount: item.unit_price,
6 hs_code: item.metadata?.hs_code,
7}));
1const {
2 createOpenBorderApiClient,
3 OpenBorderTaxProvider,
4} = require('@open-border/medusa-payment-openborder');
5
6const openBorder = createOpenBorderApiClient({
7 apiKey: process.env.OPENBORDER_API_KEY,
8 baseUrl: process.env.OPENBORDER_API_URL,
9});
10const taxProvider = new OpenBorderTaxProvider(openBorder);
11
12const quote = await taxProvider.getTaxLines(openBorderLineItems, {
13 destination_country: shippingAddress.country_code.toUpperCase(),
14 destination_region: shippingAddress.province,
15 destination_postal_code: shippingAddress.postal_code,
16 ship_from_country: 'US', // your dispatch origin — the other half of the priced lane
17 currency: cart.currency_code.toUpperCase(),
18 shipping_amount: cart.shipping_total,
19 customer: { email: cart.email },
20});
1<div id="openborder-checkout"></div>
2<script src="https://unpkg.com/@open-border/js"></script>
3<script>
4 const checkout = OpenBorder(window.OPENBORDER_PUBLISHABLE_KEY, {
5 apiBaseUrl: window.OPENBORDER_API_URL,
6 });
7
8 checkout.mount('#openborder-checkout', {
9 currency: quote.amount_breakdown.currency,
10 amount: quote.amount_breakdown.total,
11 billingDetails: {
12 email: cart.email,
13 name: cart.shipping_address?.first_name,
14 address: cart.shipping_address,
15 },
16 onSuccess: async ({ paymentMethodId }) => {
17 await fetch('/store/checkout/openborder-payment-method', {
18 method: 'POST',
19 headers: { 'Content-Type': 'application/json' },
20 body: JSON.stringify({
21 cart_id: cart.id,
22 payment_method: paymentMethodId,
23 tax_quote_id: quote.tax_quote_id,
24 }),
25 });
26 },
27 onError: (message) => console.error(message),
28 });
29</script>
1const sessionData = {
2 cart_id: cart.id,
3 payment_method: paymentMethodId,
4 openborder_tax_quote_id: quote.tax_quote_id,
5 amount_breakdown: quote.amount_breakdown,
6 shipping_amount: cart.shipping_total,
7 merchant_reference: cart.id,
8 customer: {
9 email: cart.email,
10 name: `${cart.shipping_address.first_name} ${cart.shipping_address.last_name}`.trim(),
11 },
12 billing_address: toOpenBorderAddress(cart.billing_address ?? cart.shipping_address),
13 shipping_address: toOpenBorderAddress(cart.shipping_address),
14 line_items: openBorderLineItems,
15 metadata: {
16 medusa_cart_id: cart.id,
17 },
18};
1# Open Border API
2pnpm dev
3
4# Medusa app
5OPENBORDER_API_URL=http://localhost:3000
6OPENBORDER_API_KEY=sk_test_dev
7OPENBORDER_PUBLISHABLE_KEY=pk_test_dev
1OPENBORDER_API_URL=https://api-sandbox.openborderpayments.com
2OPENBORDER_API_KEY=sk_test_...
3OPENBORDER_PUBLISHABLE_KEY=pk_test_...