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

Меч Moscow · Fashion

Нужна помощь в разработке плагина интеграции для Medusa?

Написать намНайти плагины

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

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

  • Ресурсы Medusa
  • Плагины и интеграции
  • Эксперты
  • Кейсы
  • Medusa Чат в Telegram
  • Medusa Новости в Telegram
  • Документация Gorgo
  • Связаться с нами
  • head@gorgojs.com
  • TelegramGitHub
MedusaПлагиныInpost fulfillment
I

Inpost fulfillment

InPost fulfillment provider for MedusaJS v2 - Paczkomat locker and courier integration via ShipX API

Нужна доработка этого плагина?

Связаться с нами
npm install medusa-inpost-fulfillment
Категория
Доставка
Создано
Bystrol
Версия
0.4.0
Последнее обновление
14 часов назад
Ежемесячные загрузки
757
Звезды на Github
4
npmNPMGitHubGithub
MedusaПлагиныInpost fulfillment

medusa-inpost-fulfillment

InPost fulfillment provider plugin for MedusaJS v2. Integrates with the InPost ShipX API to support Paczkomat locker and courier delivery.

🧪 Beta testers wanted

This plugin has been tested thoroughly against the InPost sandbox, but not yet end-to-end against a production InPost account. If you have production InPost ShipX credentials and are using Medusa v2, I'd love your help validating real locker and courier shipments.

What you'd get:

  • Free setup assistance
  • Priority bug fixes

Reach out by opening a GitHub issue or emailing the maintainer. Bug reports from production use are especially welcome.

Features

  • Paczkomat locker delivery () — ships to a selected InPost locker machine
  • Courier delivery () — ships to the receiver's address with automatic dispatch order creation
  • Automatic offer selection and purchase (for prepaid accounts)
  • Local InPost shipment history stored in Medusa
  • Admin API for shipment list, details, status refresh, labels, and cancellation
  • Scheduled status synchronization for active shipments
  • Self-service InPost return tickets through the InPost Returns REST API
  • Admin API and Admin UI for return list, details, labels, refresh, and scheduled synchronization
  • Shipment label retrieval (PDF/ZPL)
  • Shipment cancellation
  • Polish postal code normalization (5 digits to XX-XXX format)
  • Parcel dimensions aggregated from cart item variants

Current limitations

  • The returns flow is currently optimized for InPost Returns ticket/code/label returns, typically locker or point-based returns depending on your Returns Portal configuration.
  • Courier return pickup is not implemented yet.
  • Supported return behavior depends on the services enabled for your InPost Returns Portal account.
  • The plugin does not perform refunds, quality-control approval, or warehouse receiving workflows automatically.
  • Webhooks are not implemented yet; shipments and returns use manual refresh plus scheduled synchronization.

Prerequisites

  • MedusaJS v2 ( ^2.5.0)
  • Node.js >= 20
  • InPost ShipX API credentials (register here)

InPost API version

This plugin currently integrates with the Polish InPost ShipX v1 API:

  • Sandbox:
  • Production:

It does not yet use the newer InPost Global API ( on ). Migrating to the Global API requires separate changes to authentication, shipment payloads, label retrieval, tracking identifiers, and endpoint URLs.

Installation

npm install medusa-inpost-fulfillment

After installing or upgrading to a version that includes the InPost shipment module, run Medusa migrations:

npx medusa db:migrate

Configuration

Add the plugin to your :

import { defineConfig } from "@medusajs/framework/utils";
const inpostOptions = {
// Required
apiToken: process.env.INPOST_API_TOKEN,
organizationId: process.env.INPOST_ORGANIZATION_ID,
// Optional — use InPost sandbox environment (default: false)
sandbox: true,
// Optional — default parcel template for locker shipments
// "small" | "medium" | "large" (default: "small")
defaultParcelTemplate: "small",
// Optional — default shipment label format
// "pdf" | "zpl" (default: "pdf")
defaultLabelFormat: "pdf",
// Optional — return session token lifetime in minutes (default: 60)
returnTokenTtlMinutes: 60,
// Optional — enables self-service return tickets through InPost Returns API.
// Uses the same sandbox flag as ShipX.
returns: {
clientId: process.env.INPOST_RETURNS_CLIENT_ID,
clientSecret: process.env.INPOST_RETURNS_CLIENT_SECRET,
defaultParcelSize: "A", // "A" | "B" | "C"
magicLinkBaseUrl: "https://store.example.com/returns/session",
description: "Please secure the returned items before shipping.",
},
// Required for courier shipments — sender details
sender: {
company_name: "My Store",
first_name: "John",
last_name: "Doe",
email: "shipping@mystore.com",
phone: "500100200",
address: {
street: "Marszalkowska",
building_number: "1",
city: "Warsaw",
post_code: "00-001",
country_code: "PL",
},
},
};
export default defineConfig({
// ...
plugins: [
// Registers the plugin module, Admin API routes, scheduled jobs, and migrations.
{
resolve: "medusa-inpost-fulfillment",
options: inpostOptions,
},
],
modules: [
{
resolve: "@medusajs/medusa/fulfillment",
options: {
providers: [
// default provider
{
resolve: "@medusajs/medusa/fulfillment-manual",
id: "manual",
},
{
resolve: "medusa-inpost-fulfillment/providers/inpost",
id: "inpost",
options: inpostOptions,
},
],
},
},
],
});

The plugin registration must be placed in . It lets Medusa discover the plugin's module, Admin API routes, scheduled jobs, and migrations. Do not place in .

The fulfillment provider registration under must stay in , because it tells Medusa's fulfillment module that InPost is available as a shipping provider.

Environment variables

VariableDescription
Your InPost ShipX API token
Your InPost organization ID

Shipping options

After installing the plugin, create shipping options in the Medusa admin that use the InPost fulfillment provider. The plugin exposes two services:

Service IDDescription
Paczkomat locker delivery
Courier home delivery

Where to find your shipments

InPost uses different apps for locker and courier shipments:

  • Locker (Paczkomat) shipments — visible in Manager Paczek (sandbox: sandbox-manager.paczkomaty.pl)
  • Courier shipments — visible in WebTrucker at kurier.inpost.pl under "Przesyłki do nadania" (Shipments to send), and later under "Monitoring" once InPost processes them

Note on sandbox for courier shipments: WebTrucker has no sandbox equivalent, so courier shipments created in sandbox will not appear in any UI. In sandbox, a correctly created courier shipment will simply reach status via the API — that is the sandbox success criterion. Only production courier shipments are visible in WebTrucker.

Storefront integration

Locker delivery

For Paczkomat locker delivery, the storefront must pass (the Paczkomat machine ID) when adding a shipping method to the cart:

await sdk.store.cart.addShippingMethod(cartId, {
option_id: lockerShippingOptionId,
data: {
target_point: "WAW123", // Paczkomat machine ID
},
});

You can use the InPost Geowidget to let customers pick a Paczkomat on a map.

Courier delivery

For courier delivery, no additional data is needed — the receiver address is taken from the cart's shipping address:

await sdk.store.cart.addShippingMethod(cartId, {
option_id: courierShippingOptionId,
});

Address requirements

InPost ShipX expects the street and building number as separate address fields. The storefront checkout should collect and save them separately:

Storefront fieldMedusa shipping address fieldRequired
First nameYes
Last nameYes
StreetYes
Building numberYes
Postal codeYes
CityYes
CountryYes
PhoneYes
CompanyNo
State / provinceNo
Apartment / flat numberNo

Do not put the full street address with building number into (for example ). Use for the street name only and for the building number.

If the storefront has a single field, split it into separate and inputs before using this provider.

Parcel dimensions

For courier shipments, the plugin aggregates parcel dimensions from cart item variants (the , , , and fields on product variants). If no dimensions are available, must be provided in fulfillment data. The plugin does not silently fall back to placeholder parcel dimensions.

For locker shipments, a parcel template (, , or ) is used instead, configurable via the option or per-shipment via in fulfillment data.

InPost shipment history

The plugin includes an module that stores a local record after a ShipX shipment is created successfully. This makes shipment data available outside of and gives the admin API a stable source for list/detail views and status synchronization.

Local shipment history is recorded asynchronously: after Medusa creates an order fulfillment, the plugin listens to the event, reads the InPost shipment data from , and upserts an record.

Stored fields include:

Admin API

The following admin routes are available:

MethodPathDescription
List local InPost shipments
Retrieve one local shipment
Refresh shipment data from ShipX
Download shipment label
Cancel shipment in ShipX if allowed
List local InPost returns
Retrieve one local return with items
Refresh return data from InPost Returns API
Download return label PDF when available

List filters: , , , , , , , , , , , , and .

Return list filters: , , , , , , , , , , , , , , and .

Supported list filter values:

Query paramDescription
Searches order ID, fulfillment ID, shipment ID, tracking number, and dispatch order ID
or
or
or
Shipment creation date lower bound,
Shipment creation date upper bound,

Label download accepts an optional query parameter:

/admin/inpost/shipments/:id/label?format=pdf
/admin/inpost/shipments/:id/label?format=zpl

Active shipments are synchronized every 15 minutes by the scheduled job.

Active return tickets are synchronized every 30 minutes by the scheduled job. The job processes local returns with a and skips final statuses: , , , , and .

Admin UI

The plugin adds an Admin UI extension under InPost. The shipments view uses the plugin Admin API and lets store staff:

  • browse locally recorded InPost shipments,
  • search by order ID, fulfillment ID, ShipX shipment ID, tracking number, receiver, or destination,
  • filter by status, service type, and sync errors,
  • refresh shipment data from ShipX,
  • download PDF or ZPL labels,
  • open public InPost tracking,
  • copy the tracking number,
  • cancel cancellable shipments,
  • inspect the raw ShipX response.

The plugin also adds an order details widget showing InPost shipments recorded for the current order.

The Admin UI groups shipments and returns under one InPost sidebar entry with internal tabs. The returns list uses server-side pagination and filters persisted in the URL, including status, return method, order ID, customer email, sync errors, and creation date range.

Return details are available from the returns list. The drawer shows returned items, return code, tracking number, expiration date, last sync/error fields, and the raw InPost Returns API response. Store staff can refresh return data from InPost, copy the return code or tracking number, open the Medusa order, and download the return label when the ticket has a .

The InPost Returns REST API exposes return ticket lookup through the list endpoint, not a single-ticket status endpoint. The plugin refreshes one local return by querying across the known InPost return statuses in a date window around the local return creation date, then matching the remote ticket by .

How it works

Fulfillment flow

  1. Create shipment — sends parcel, receiver, and sender data to InPost ShipX API
  2. Offer handling — for prepaid accounts, the plugin polls for offers, selects the first available one, and purchases it
  3. Dispatch order (courier only) — creates a dispatch order to schedule courier pickup from the sender's address
  4. Return data — stores , , and in the fulfillment data
  5. Local history — after Medusa emits , the plugin upserts an record in the module

Cancellation

When a fulfillment is cancelled in Medusa, the plugin attempts to cancel the corresponding shipment in InPost.

ShipX cancellation is only possible before the shipment is confirmed. The plugin treats the following statuses as cancellable through the API:

Once a shipment reaches , ShipX rejects cancellation with . In that case, the plugin does not call the cancellation endpoint and lets Medusa cancel the fulfillment locally only. The physical shipment must then be cancelled manually in InPost Manager for locker shipments or WebTrucker for courier shipments.

The Admin UI disables the Cancel shipment action for non-cancellable statuses and shows a tooltip explaining that the shipment must be cancelled manually in InPost.

See the official InPost ShipX cancellation docs: Anulowanie przesyłki.

Labels

The plugin supports retrieving shipment labels as PDF documents through Medusa's fulfillment documents API.

Returns

Medusa's default fulfillment-provider return flow does not provide enough data to create a full InPost return shipment automatically (for example, it does not include the customer's selected return locker). For that native Medusa flow, intentionally does not call ShipX.

The plugin includes the first part of a self-service return flow:

MethodPathDescription
Looks up an order by and , then prepares a hashed return-session token if the order matches
Validates a return-session token and returns safe order/item data plus created return-ticket data for the return UI
Submits a return request from an active return-session token and creates an InPost return ticket if Returns API credentials are configured
Downloads the return label PDF for an active return session, when the InPost return ticket has a label

Lookup request body:

{
"order_id": "order_...",
"email": "customer@example.com",
"return_method": "locker"
}

is optional and defaults to .

Submit return request body:

{
"token": "return-session-token",
"items": [
{
"order_line_item_id": "ordli_...",
"quantity": 1,
"reason": "Wrong size"
}
]
}

The submit endpoint validates that the token is active, the requested items belong to the order, the quantities are returnable, and the same line items have not already been submitted in another active InPost return. It stores the selected items in , creates a return ticket through the InPost Returns REST API, and moves the local return to .

Depending on the InPost Returns Portal settings for your account, the response can include:

  • — code for sending a return without a printed label
  • — label URL for labeled return shipments
  • — return shipment tracking number
  • — return ticket expiration date

At this stage, the self-service returns flow is intended for InPost Returns ticket/code/label returns. Courier pickup for returns is not implemented yet, even though is typed to allow future support.

If the return response contains a , the storefront can download the label through:

curl "http://localhost:9000/store/inpost/returns/RETURN_ID/documents?token=RETURN_SESSION_TOKEN" \
-H "x-publishable-api-key: pk_..."

The endpoint validates that the token belongs to the requested return and is still active. If your InPost Returns Portal account is configured for code-only returns, is empty and this endpoint returns a error; show the to the customer instead.

If the InPost Returns API call fails, the local return is marked as and stores the API error. Retrying the same request with the same active token reuses the existing local return items and attempts ticket creation again.

The lookup endpoint always returns the same neutral response, so it does not reveal whether an order exists. The raw token is never stored; only a SHA-256 hash and expiration date are saved in .

If is configured and the lookup data matches an order, the plugin emits an event. The event contains a ready-to-send magic link with the token added as a query parameter.

Event payload:

type InPostReturnSessionCreatedEvent = {
email: string
order_id: string
inpost_return_id: string
return_method: "locker" | "point" | "courier" | (string & {})
magic_link: string
token_expires_at: Date | string | null
}

The plugin does not send emails directly. Add a subscriber in your Medusa app and call your email or notification provider from there:

import { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
type InPostReturnSessionCreatedEvent = {
email: string
order_id: string
inpost_return_id: string
return_method: string
magic_link: string
token_expires_at: string | Date | null
}
export default async function sendInPostReturnMagicLink({
event: { data },
container,
}: SubscriberArgs<InPostReturnSessionCreatedEvent>) {
const logger = container.resolve("logger")
logger.info(
`Send InPost return magic link for order ${data.order_id} to ${data.email}: ${data.magic_link}`
)
// Call your email provider here.
}
export const config: SubscriberConfig = {
event: "inpost.return_session_created",
}

Options reference

OptionTypeRequiredDefaultDescription
Yes—InPost ShipX API token
Yes—InPost organization ID
NoUse sandbox API environment
NoDefault parcel template for locker shipments
NoDefault label format for shipment documents
NoStore API return-session token lifetime
For returns—InPost Returns REST API OAuth client ID
For returns—InPost Returns REST API OAuth client secret
Noaccount defaultDefault parcel size for return tickets
No—Absolute storefront URL used to build return-session magic links
Noaccount defaultReceiver override for return tickets
No—Description shown to the return sender
For courier—Sender details (required for courier shipments)
For courier—Sender company name
For courier—Sender first name
For courier—Sender last name
Yes—Sender email
Yes—Sender phone number
Yes—Sender address

License

MIT

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

Посмотреть все
Доставка
DHL eCommerce logo

DHL eCommerce

От Mitchellston

Выполняйте заказы с помощью DHL eCommerce

Загрузка данных
GitHubnpm
Доставка
Mondial Relay logo

Mondial Relay

От Theodaguier

Доставляйте заказы с Mondial Relay

Загрузка данных
npm
Доставка
ApiShip logo

ApiShip

От Gorgo

Подключите доставку несколькими перевозчиками

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