• Сообщество
  • Блог
Документация
Плагины и интеграцииВсе расширения для Medusa от сообществаСтартерыЗапускайте проекты быстрее с готовыми решениями
ЭкспертыПодберите специалиста для разработки и развития вашего проекта на MedusaКейсыПосмотрите примеры Medusa в продакшене и успешные внедрения
Меч Moscow
Комплексная e-commerce платформа на Medusa для московского fashion-бренда

Меч Moscow · Fashion

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

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

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

Peach payments

Unofficial Peach Payments payment provider for Medusa v2

npm install medusa-payment-peach-payments
Категория
Платежи
Создано
Max-bissolati
Версия
0.1.0
Последнее обновление
10 часов назад
Ежемесячные загрузки
Загрузка данных
Звезды на Github
0
npmNPMGitHubGithub

medusa-payment-peach-payments

An unofficial Peach Payments (Checkout V2) payment provider for Medusa v2. It was extracted from a production Medusa 2.13 store that has been taking live Peach traffic, and it carries over the parts of that integration worth keeping: checkout creation, authorize-on-return completion with an amount-integrity check, webhook handling that re-confirms the outcome server-to-server before trusting it, and V1 HMAC refunds.

This project is not affiliated with, endorsed by, or supported by Peach Payments. It is a community plugin maintained independently. If you hit a Peach API question that isn't about this plugin's code, go to developer.peachpayments.com or Peach's own support channels.

Requirements

  • Medusa v2, and (peer dependencies, not bundled: install them yourself if your project doesn't already have them).
  • Node.js 20 or newer.
  • A Peach Payments merchant account with Checkout V2 access, and (for testing) a sandbox entity. Peach's sandbox is requested through your account manager or support; see Sandbox.

Install

npm install medusa-payment-peach-payments

Registration

Payment providers in Medusa v2 are registered inside the Payment module's array, not the top-level array. Add this to :

1import { defineConfig } from "@medusajs/framework/utils"
2
3module.exports = defineConfig({
4 modules: [
5 {
6 resolve: "@medusajs/medusa/payment",
7 options: {
8 providers: [
9 {
10 resolve: "medusa-payment-peach-payments/providers/peach",
11 id: "peach",
12 options: {
13 // "sandbox" or "production". Default "sandbox". Drives which Peach
14 // hosts (OAuth, Checkout API, SDK script) the provider talks to.
15 mode: process.env.PEACH_MODE,
16
17 // OAuth credentials from the Peach Dashboard (Checkout API access).
18 clientId: process.env.PEACH_CLIENT_ID,
19 clientSecret: process.env.PEACH_CLIENT_SECRET, // secret
20 merchantId: process.env.PEACH_MERCHANT_ID,
21
22 // The Checkout entity id. Doubles as the `authentication.entityId`
23 // sent to Peach and the `key` the storefront passes to the SDK's
24 // Checkout.initiate() call, so it goes to the browser (not a secret,
25 // but treat it as semi-public rather than committing it to source).
26 entityId: process.env.PEACH_ENTITY_ID,
27
28 // HMAC signing key used for webhook verification AND the V1 refund
29 // endpoint. Refunds need this even if you never wire up webhooks.
30 secretToken: process.env.PEACH_SECRET_TOKEN, // secret
31
32 // The storefront origin Peach allowlists. Sent as the Origin/Referer
33 // headers on checkout creation. Peach validates the domain, not an
34 // IP. No trailing slash.
35 referer: process.env.PEACH_REFERER,
36
37 // Your webhook URL, registered with Peach (see Webhooks below).
38 // Medusa derives the actual route from the provider id; this option
39 // just tells Peach where to send its POST.
40 notificationUrl: process.env.PEACH_NOTIFICATION_URL,
41
42 // Where Peach returns the shopper after paying (embedded and hosted
43 // both use this).
44 shopperResultUrl: process.env.PEACH_SHOPPER_RESULT_URL,
45
46 // Where Peach sends the shopper if they cancel a hosted-redirect
47 // payment. Not used by the embedded widget.
48 cancelUrl: process.env.PEACH_CANCEL_URL,
49
50 // "DB" = capture immediately (the common case for physical goods).
51 // "PA" = pre-authorise, capture later. Default "DB".
52 paymentType: process.env.PEACH_PAYMENT_TYPE,
53
54 // Display name shown in the Peach checkout UI.
55 merchantName: process.env.PEACH_MERCHANT_NAME,
56
57 // Fallback currency used only when a payment session or refund
58 // carries none of its own. With no session currency and no default
59 // set, the provider throws rather than guessing. Peach's business is
60 // ZAR-centric, but this option does not default to ZAR: set it
61 // explicitly for your store.
62 defaultCurrency: process.env.PEACH_DEFAULT_CURRENCY,
63
64 // Fallback billing country (ISO alpha-2, e.g. "ZA") used when a cart
65 // address has none. Left unset, the country field is omitted
66 // entirely rather than guessed.
67 defaultCountryCode: process.env.PEACH_DEFAULT_COUNTRY_CODE,
68
69 // Optional per-result-code overrides, checked before the built-in
70 // mapping. Not a plain string, so there's no single env var for it:
71 // set it directly in code if you need it, e.g.:
72 // resultCodeOverrides: { "000.400.101": "authorized" }
73 // Overriding a code the built-in map treats as a decline/error logs
74 // a warning once, since it loosens a fail-closed default.
75 },
76 },
77 ],
78 },
79 },
80 ],
81})

The runtime provider id Medusa registers is . With the identifier fixed at and as above, that's . If you pick a different (e.g. ), the provider id changes to match (). Whatever it resolves to is the your storefront selects when creating a payment session, and it's also the segment Medusa uses to build the webhook URL (see below). For the exact shape and defaults of every option, read the JSDoc on the exported type:

import type { PeachOptions } from "medusa-payment-peach-payments/providers/peach"

Note that a bare (or ) is not exported, by design: there is no meaningful package root for a Medusa plugin. Always import the provider subpath, , as shown in the registration snippet.

Environment variables

None of these are required by Medusa itself, they're just the convention this README uses above. Name them however fits your project.

Env varOptionNotes
or , default
secret
sent to the browser, not a secret
secret; webhook HMAC + refund HMAC
your storefront origin, no trailing slash
your webhook URL, see below
where the shopper returns to after paying
hosted-redirect cancel target
or , default
fallback only, no ZAR default baked in
fallback only

Completion model

There are two independent paths to completing a payment, and only one of them needs to work for an order to go through:

  • Primary: authorize-on-return. The shopper is redirected back to after paying. The storefront calls , Medusa calls the provider's , which polls and maps the result code to a Medusa payment status. A success creates the order right there.
  • Backup: the webhook. Peach also POSTs to your registered webhook URL. Medusa's built-in webhook route calls the provider's , which verifies the signature, re-confirms the outcome and amount against , and only then tells Medusa to authorise or capture. This covers a shopper who closes the tab before the redirect completes.

Both paths converge on the same call as the source of truth for the outcome and the amount, so neither one can complete an order on the strength of an unverified webhook body or a client-reported success alone.

Webhooks

No custom route is needed on your end. Medusa auto-mounts for every registered payment provider and routes incoming POSTs to the provider's . With the registration above (), that's , so the URL to register with Peach is:

https://your-backend.example.com/hooks/payment/pp_peach_peach

Register that URL in the Peach Dashboard/Console as your checkout's webhook endpoint, and set the same value as in the provider options so Peach knows to expect it. Peach then surfaces a signing secret when you add the webhook: that becomes your .

You don't need to configure a body parser for this route. Medusa parses the incoming webhook body itself, and the provider handles both cases: verifying the signature from the raw body when it's preserved, and reconstructing the same signed message from Medusa's already-parsed body when it isn't. Either way, verification fails closed: an unverifiable webhook is ignored, never trusted. See for the signature scheme and the full verification path. Peach's own reference is at developer.peachpayments.com/docs/checkout-webhooks.

Refunds

Refunds go through Peach's older V1 endpoint (), signed with the same HMAC key as webhooks. That means is required for refunds even in a setup that never receives a webhook. The refund body is sent as flat, form-encoded key-value pairs (not nested JSON) with a V1 HMAC signature over the sorted keys. Peach's checkout API and its refund endpoint are genuinely two different signing schemes, which is easy to trip over if you're building this from scratch. Peach also returns HTTP 200 for a declined refund, so the provider checks the result code itself and throws rather than reporting a declined refund as a success.

Refunds need the original payment's transaction id (not the ). The provider stores it on the payment session's data after a successful authorization, and reads it back for the refund call. If that id is missing (for example, a payment authorised before this provider recorded it), throws a clear error rather than guessing or silently no-oping.

Testing in sandbox

Set and use your sandbox entity's credentials. Peach's sandbox bypasses the success screen and OTP/challenge prompts for known test cards, redirecting straight to . A few of the published test cards (any future expiry date; CVV is 3 digits for Visa/Mastercard, 4 for Amex):

SchemeCard numberOutcome
Visafrictionless success
Mastercardfrictionless success
Amexfrictionless success

The full list, including challenge-flow and decline scenarios, is in Peach's test and go-live reference.

Hardening

This provider does a few things beyond the minimum contract, carried over from running against live traffic:

  • Amount-integrity gate. cross-checks the amount Peach reports on against the amount the session was created for, and fails closed () on any mismatch or a missing Peach amount. A result code alone is never enough to complete an order.
  • Webhook re-confirmation. The webhook handler does not act on the notification payload's claimed outcome or amount. It re-fetches by and uses that response as the only source of truth, as defense in depth: trusting only a fresh server-to-server status lookup makes the outcome independent of anything in the notification body.
  • Conservative result-code mapping. and (3DS "not participating"/"not enrolled" codes) map to , not success. They're intermediate, risk-adjacent codes rather than terminal successes, and Checkout V2's real successes land on a terminal code instead.
  • Refund success can't be loosened by . Overrides only affect the authorize/webhook status mapping; a refund is still validated against its own result code regardless of what overrides are configured elsewhere.

None of this is exotic. It's what you'd want from any payment integration, but it's worth being explicit about, since it's the main reason to reach for a maintained provider instead of a quick custom one.

Storefront integration

This package is backend-only; there's no npm-installable storefront SDK because Peach's Checkout widget itself has none (it's a script-tag global, not an npm package). has reference React/Next.js code adapted from a real integration: reading the session off the cart, mounting the embedded widget, and handling the return redirect. See for the full flow and what to adapt.

Limitations

  • Two-decimal currencies only. Amounts are formatted and compared at 2 decimal places ( rounds to the cent; forces ). Zero-decimal currencies (e.g. JPY) and three-decimal currencies are not supported. Amounts beyond roughly 9e13 in minor units lose float precision and are out of scope: this provider targets 2-decimal currencies at realistic order magnitudes only.
  • No built-in ZAR default. Peach's own business is ZAR-centric, but this provider does not assume ZAR anywhere. Set yourself if you want a fallback.
  • No cancel endpoint. Peach's V2 API has no way to cancel a checkout server-side; is a no-op and unpaid checkouts simply expire after 30 minutes.
  • Capture is a no-op for . Immediate-capture payments settle at Peach when the shopper pays; there's nothing for to do. Pre-auth () capture/void uses a separate Peach API this provider does not implement. See Peach's docs on capture and reversal.

License

MIT, see . This is an independent, community-maintained project with no affiliation to Peach Payments; use it at your own risk and test thoroughly against your own Peach account before taking live payments.

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

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

Braintree

От Lambda Curry

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

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

Pay.

От Webbers

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

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

Mollie

От Variable Vic

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

Загрузка данных
GitHubnpm