• Модуль интеграций
  • Сообщество
  • Блог
Документация
Плагины и интеграцииВсе расширения для Medusa от сообществаСтартерыЗапускайте проекты быстрее с готовыми решениями
ЭкспертыПодберите специалиста для разработки и развития вашего проекта на MedusaКейсыПосмотрите примеры Medusa в продакшене и успешные внедрения
Т-Касса от Т-Банка для Medusa: приём платежей для РФ

16 октября 2026 г. · Продукт

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

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

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

Medusajs plugin pos payments

Плагин Medusa v2 для платежей через бразильские POS-терминалы. Общая платформа и адаптеры под каждого эквайера работают за одним провайдером pos-terminal.

npm install @voolulabs/medusajs-plugin-pos-payments
Категория
Платежи
Создано
Voolulabs
Версия
0.1.0
Последнее обновление
3 дня назад
Ежемесячные загрузки
Загрузка данных
Звезды на Github
0
npmNPMGitHubGithub

Medusa POS Payments

In-person Brazilian card-terminal (maquininha) payments for Medusa v2.

adds a payment provider family to Medusa so a point-of-sale front end can take BRL payments made on physical card terminals (cash, card, Pix, bank transfer). Phase 1 ships the manual / terminal-present flow: the cashier confirms the charge made on the terminal, and the backend records the payment state. Acquirer adapters (Mercado Pago Point, SumUp, Stone, Cielo) plug into the same provider in later phases.

Documentation | Medusa Website | Medusa Repository

Features

  • payment provider registered as , , ,
  • Manual / terminal-present flow: no acquirer credentials required in Phase 1
  • Authenticated health endpoint
  • Provider ids consumed verbatim by the POS app from — zero front-end changes
  • State kept in Medusa payment / (JSONB) — no migrations, no extra tables
  • Hardened session-data handling: zod validation at the boundary, prototype-pollution rejection

Prerequisites

  • Medusa v2 backend — >= 2.19
  • Node.js >= 20

How to Install

  1. Run the following command in your Medusa backend project:

  2. Enable the manual providers in your :

  3. In , register the plugin (routes) and the provider(s) (payment module):

  4. Enable the providers on the region your POS uses (e.g. in the seed or via the admin API).

Mercado Pago (terminal charges — Fase 2)

Register the provider on the payment module (alongside or instead of the manual ones) and provide the credentials via environment (never literals — CONSTRAINTS 8):


Webhooks and Reconciliation (mercadopago)

The provider registers a native webhook handler at . Point your Mercado Pago application webhook at the full URL (application-level config in the developer panel; the panel summary shows only the domain — configure the complete path).

The core Medusa payment module emits the webhook event on an internal queue with and a ms by default. Mercado Pago retries its delivery for up to 22s and only while it does NOT receive a 2xx — so if every internal attempt fails, a terminal-originated refund could stay unreconciled. Two defenses, use both:

  1. Raise the internal budget on the payment module ( / are core options read from the payment module registration — verified in the 2.19 hook route):

  2. Scheduled reconciliation job (registered automatically by this plugin, daily at 04:00): scans captured payments of from the last 30 days (the charge state lives in , written by the provider's capture/refund), re-fetches each charge from the Mercado Pago Orders API and reconciles refunds that were missed by the event bus, reusing the same idempotent decision and transaction id as the webhook subscriber. The guard is the Medusa payment's refunds list; job×subscriber parallelism is serialized by the core's refund row lock ( under a mandatory transaction, verified in 2.19.0) plus the refund idempotency key at the acquirer — engine-level mutual exclusion remains a T5 residual tracked in ADR 0007. Volume: one GET per captured payment within the window, sequential, per daily run. The job is presence-gated: without the block it does nothing.

The plugin also keeps both entries in your honest: if the provider entry of the payment module and the plugin's block diverge (token/secret/test mode), the provider fails to resolve with the diverging key NAMES (providers are constructed lazily — first session, webhook or capture). Manual providers (///) are exempt, since they do not consume the block.


Cancellation contract (mercadopago)

maps the Mercado Pago Orders API contract by charge state (official .mx docs, 2026-10-07 — note that Mercado Pago's docs currently diverge by region AND language; the .br pages are stale):

Charge state at MPHTTPBody
200 with (synchronous cancel)
202 with and — the cancellation is REQUESTED, not done: the order stays until the webhook/poll confirms, and the terminal may prioritize the charge and capture anyway
/ / 409 — refusal body is a public contract of this plugin
already canceled200re-fetch confirms (idempotent); a diverging re-fetch answers 409 with the real ( is when the re-fetch itself fails)
any other state echoed by a 2xx cancel202defensive: a successful cancel over is async by contract — the body carries the state verbatim

The header is sent unconditionally (MP ignores it for and requires it for ). Poll responses carry while the cancellation is in flight. Idempotency keys are canonical UUIDv5 under a plugin-fixed namespace — deterministic, so retrying the same operation reuses the same key (docs accept "UUID v4 or random string"): for cancel, for create, for refund.


Merchant Onboarding (mercadopago — Fase 2b)

Merchants connect their own Mercado Pago account from the Medusa Admin (Settings → POS Payments) — no platform-held merchant token required for onboarding. The charging provider keeps using the platform until the per-merchant cutover (1.0.0 decision); the onboarding platform itself is fully merchant-scoped.

Platform configuration (deploy-side, never per-merchant)

Every value can also be provided as plugin options ( in ); environment takes precedence. Missing pieces fail closed with a typed error (). Run on deploy — the onboarding module's tables do not migrate on .

Routes (admin, core auth — bearer for the POS app, session cookie for the Admin UI)

RoutePurpose
Per-acquirer connection summary (non-sensitive)
Detail · pasted credential (validate-then-activate) · disconnect (purge secrets, keep audit)
Emits single-use + (OAuth)
Revalidates now ( / ) with lazy token refresh
· Stores/POS CRUD (MP §10.1) — binding: store = Medusa unit, POS = stock location
Selected terminal — global default or per-register binding
Registers reported by the POS app ("Terminais por caixa")
Plugin health + non-sensitive connection summary
Public OAuth callback — protected by the single-use server-side , 302 back to the Admin

Security properties: merchant tokens are encrypted at rest (AES-256-GCM envelope, master key outside the database) and never appear in API responses, URLs or logs; is CSPRNG, expires in ≤10 min and is consumed once; refresh rotates the token pair atomically (lazy single-flight); moves the connection to — never a silent fallback to the platform token. Every onboarding operation is audited (actor + acquirer + timestamp, minimal payload).


Test the Plugin

  1. Run your Medusa backend ( / ).

  2. Log in and list the providers enabled on your POS region — on Medusa 2.19 the listing lives on the Store API:

    The providers must be listed (the admin API does not expose this route on 2.19).

  3. Place a test order with the provider (draft order → payment collection → payment session → mark as paid) and confirm is with the provider id preserved.


Additional Resources

  • Medusa Payment Provider Reference
  • Creating a Plugin
  • Acquirer adapter roadmap and architecture decisions: in this repository

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

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

Braintree

От Lambda Curry

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

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

Pay.

От Webbers

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

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

Mollie

От Variable Vic

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

Загрузка данных
GitHubnpm
npm install @voolulabs/medusajs-plugin-pos-payments
POS_PAYMENTS_MANUAL=true
1// 1. routes — in the top-level `plugins` array:
2plugins: [
3 // ...
4 {
5 resolve: "@voolulabs/medusajs-plugin-pos-payments",
6 options: {},
7 },
8]
9
10// 2. provider — in `modules`, on the payment module:
11modules: [
12 {
13 resolve: "@medusajs/payment",
14 options: {
15 providers: [
16 ...(process.env.POS_PAYMENTS_MANUAL === "true"
17 ? ["card", "pix", "cash", "transfer"].map((method) => ({
18 resolve: "@voolulabs/medusajs-plugin-pos-payments/providers/pos-terminal",
19 id: method,
20 options: { acquirer: "manual" },
21 }))
22 : []),
23 ],
24 },
25 },
26]
1// in `modules`, on the payment module providers array:
2{
3 resolve: "@voolulabs/medusajs-plugin-pos-payments/providers/pos-terminal",
4 id: "mercadopago",
5 options: {
6 acquirer: "mercadopago",
7 accessToken: process.env.MP_ACCESS_TOKEN, // App_USR-... (publisher/merchant token)
8 webhookSecret: process.env.MP_WEBHOOK_SECRET, // x-signature secret from the DevPanel
9 // mpPointTestMode: true, // sandbox virtual terminal (SBX*) — dev/homologation only
10 },
11}
1# .env
2MP_ACCESS_TOKEN=APP_USR-...
3MP_WEBHOOK_SECRET=...
4# POS_PAYMENTS_MP_TEST=true # alternative to the option above
1modules: [
2 {
3 resolve: "@medusajs/payment",
4 options: {
5 webhook_retries: 6, // default 3
6 webhook_delay: 10000, // default 5000
7 providers: [/* ... */],
8 },
9 },
10]
1# .env of the Medusa backend
2POS_PAYMENTS_MASTER_KEY=<hex 32 bytes> # AES-256-GCM envelope for merchant credentials (engenharia §3.4)
3POS_PAYMENTS_MP_CLIENT_ID=<app client id> # OAuth app (Point solution) from the DevPanel
4POS_PAYMENTS_MP_CLIENT_SECRET=<app client secret> # exists after production credentials activation
5POS_PAYMENTS_MP_REDIRECT_URI=https://<host>/pos-payments/callback/mercadopago # EXACT match, registered in the app
6POS_PAYMENTS_MP_OAUTH_TEST_TOKEN=true # sandbox exchanges (test_token=true) — dev only
7POS_PAYMENTS_ADMIN_PATH=/app # admin.path of the host (OAuth callback redirect base)
1curl "http://<backend>:9000/store/payment-providers?region_id=<region>" \
2 -H "x-publishable-api-key: pk_..."