npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

medusa-plugin-boxtal-v2

v0.1.0

Published

Medusa.js v2 plugin for Boxtal: relay point search, shipping orders, labels, tracking, and fulfillment provider (Mondial Relay / Chronopost via Boxtal API v3).

Readme

medusa-plugin-boxtal-v2

Plugin Medusa.js v2 pour Boxtal API v3 :

  • Provider de fulfillment (Mondial Relay point relais + Chronopost domicile)
  • Recherche / détail de points relais (Store API)
  • Création d’expédition, étiquettes PDF, tracking
  • Webhooks HMAC (DOCUMENT_CREATED, TRACKING_CHANGED)
  • Calcul poids / dimensions / valeur déclarée depuis les produits

Compatible Medusa ≥ 2.12.


Table des matières

  1. Installation
  2. Configuration backend
  3. Variables d’environnement
  4. Créer les shipping options
  5. Webhooks
  6. API référence
  7. Intégration storefront
  8. Admin — sync étiquette
  9. Comportement à la commande
  10. Troubleshooting

1. Installation

npm install medusa-plugin-boxtal-v2
# ou
yarn add medusa-plugin-boxtal-v2

Développement local (yalc)

# dans medusa-plugin-boxtal-v2
npm run build
npx medusa plugin:publish

# dans votre app Medusa
npx medusa plugin:add medusa-plugin-boxtal-v2

Ou dépendance fichier :

{
  "dependencies": {
    "medusa-plugin-boxtal-v2": "file:../medusa-plugin-boxtal-v2"
  }
}

2. Configuration backend

Deux enregistrements sont obligatoires dans medusa-config.ts :

  1. plugins — charge les routes API, middlewares webhook, subscribers
  2. fulfillment.providers — enregistre le provider boxtal
import { defineConfig, loadEnv } from "@medusajs/framework/utils"

loadEnv(process.env.NODE_ENV || "development", process.cwd())

module.exports = defineConfig({
  plugins: [
    {
      resolve: "medusa-plugin-boxtal-v2",
      options: {},
    },
  ],
  modules: [
    {
      resolve: "@medusajs/medusa/fulfillment",
      options: {
        providers: [
          {
            resolve: "@medusajs/medusa/fulfillment-manual",
            id: "manual",
          },
          {
            resolve: "medusa-plugin-boxtal-v2/providers/boxtal",
            id: "boxtal",
            options: {
              accessKey: process.env.BOXTAL_ACCESS_KEY,
              secretKey: process.env.BOXTAL_SECRET_KEY,
              environment: process.env.BOXTAL_ENVIRONMENT || "sandbox",
              apiBaseUrl: process.env.BOXTAL_API_BASE_URL,
              relayOfferCode: process.env.BOXTAL_RELAY_OFFER_CODE,
              homeOfferCode: process.env.BOXTAL_HOME_OFFER_CODE,
              relayName: process.env.BOXTAL_RELAY_NAME,
              relayTypeLabel: process.env.BOXTAL_RELAY_TYPE_LABEL,
              relayDescription: process.env.BOXTAL_RELAY_DESCRIPTION,
              homeName: process.env.BOXTAL_HOME_NAME,
              homeTypeLabel: process.env.BOXTAL_HOME_TYPE_LABEL,
              homeDescription: process.env.BOXTAL_HOME_DESCRIPTION,
              labelType: process.env.BOXTAL_LABEL_TYPE || "PDF_A4",
              contentCategoryId: process.env.BOXTAL_CONTENT_CATEGORY_ID,
              contentDescription: process.env.BOXTAL_CONTENT_DESCRIPTION,
              sender: {
                firstName: process.env.BUSINESS_FIRSTNAME,
                lastName: process.env.BUSINESS_LASTNAME,
                street: process.env.BUSINESS_STREET,
                houseNo: process.env.BUSINESS_HOUSE_NO,
                countryCode: process.env.BUSINESS_COUNTRY_CODE || "FR",
                postcode: process.env.BUSINESS_POSTCODE,
                city: process.env.BUSINESS_CITY,
                phone: process.env.BUSINESS_PHONE,
                email: process.env.BUSINESS_EMAIL,
                company: process.env.BUSINESS_COMPANY,
              },
            },
          },
        ],
      },
    },
  ],
})

ID runtime du provider

Medusa compose {id}_{identifier}boxtal_boxtal.

Utilisez cet ID pour détecter les options shipping côté storefront :

option.provider_id?.includes("boxtal")

3. Variables d’environnement

Copiez dans le .env de votre backend Medusa :

# --- Boxtal API ---
BOXTAL_ACCESS_KEY=
BOXTAL_SECRET_KEY=
BOXTAL_ENVIRONMENT=sandbox
# Production : https://api.boxtal.com  |  Sandbox : https://api.boxtal.build
BOXTAL_API_BASE_URL=https://api.boxtal.build

# Offres (codes fournis par Boxtal)
BOXTAL_RELAY_OFFER_CODE=MONR-CpourToi
BOXTAL_HOME_OFFER_CODE=CHRP-Chrono18

# Libellés checkout (optionnel)
BOXTAL_RELAY_NAME=Mondial Relay - Livraison en point Relais
BOXTAL_RELAY_TYPE_LABEL=Point Relais
BOXTAL_RELAY_DESCRIPTION=Livraison en point relais — 3 à 5 jours ouvrés
BOXTAL_HOME_NAME=Chronopost - Livraison à domicile
BOXTAL_HOME_TYPE_LABEL=Domicile
BOXTAL_HOME_DESCRIPTION=Livraison à domicile — 1 jour ouvré

# Tarifs flat (euros) utilisés par le script setup
BOXTAL_RELAY_PRICE=5.9
BOXTAL_HOME_PRICE=7.9

# Étiquette & contenu colis
BOXTAL_LABEL_TYPE=PDF_A4
BOXTAL_CONTENT_CATEGORY_ID=content:v1:80500
BOXTAL_CONTENT_DESCRIPTION=Articles de décoration artisanale

# Valeur déclarée : items (marchandises) | order_total (total payé)
BOXTAL_DECLARED_VALUE_MODE=items

# Fallback dimensions si produit sans L/W/H (cm)
BOXTAL_DEFAULT_PACKAGE_LENGTH_CM=30
BOXTAL_DEFAULT_PACKAGE_WIDTH_CM=20
BOXTAL_DEFAULT_PACKAGE_HEIGHT_CM=10

# Webhooks
BOXTAL_WEBHOOK_SECRET=
BOXTAL_WEBHOOK_CALLBACK_URL=https://votre-domaine.com/hooks/boxtal

# Expéditeur (obligatoire pour créer une shipping-order)
BUSINESS_FIRSTNAME=
BUSINESS_LASTNAME=
BUSINESS_COMPANY=
BUSINESS_STREET=
BUSINESS_HOUSE_NO=
BUSINESS_POSTCODE=
BUSINESS_CITY=
BUSINESS_COUNTRY_CODE=FR
BUSINESS_PHONE=
BUSINESS_EMAIL=

# Requis pour le calcul poids/dims à l’expédition
DATABASE_URL=

4. Créer les shipping options

Après configuration, créez les 2 options (relais + domicile) liées au provider :

# Depuis le code source du plugin (recommandé en monorepo)
cd medusa-plugin-boxtal-v2
# Pointer DATABASE_URL vers la DB de l’app, puis :
npx medusa exec ./src/scripts/setup-boxtal-shipping.ts

Ou copiez src/scripts/setup-boxtal-shipping.ts dans votre app et exécutez-le avec medusa exec.

Le script crée :

| Code type | data.deliveryType | Usage | |-----------|---------------------|--------| | boxtal-relay | relay | Point relais (sélection obligatoire) | | boxtal-home | home | Livraison à domicile |

Assurez-vous que vos produits ont un shipping profile relié à la même zone France que le script.


5. Webhooks

  1. Exposez publiquement POST /hooks/boxtal (tunnel Cloudflare / ngrok en local).
  2. Définissez BOXTAL_WEBHOOK_SECRET et BOXTAL_WEBHOOK_CALLBACK_URL.
  3. Enregistrez les subscriptions :
npx medusa exec ./src/scripts/setup-boxtal-webhook.ts
npx medusa exec ./src/scripts/list-boxtal-webhooks.ts

Événements gérés : DOCUMENT_CREATED (étiquette), TRACKING_CHANGED (suivi).

Le middleware du plugin active preserveRawBody sur /hooks/boxtal pour la vérif HMAC (x-bxt-signature).


6. API référence

Toutes les routes Store nécessitent le header x-publishable-api-key.

GET /store/boxtal/relay-points

Recherche de points relais.

Query params :

| Param | Type | Description | |-------|------|-------------| | zipCode | string | Code postal (recommandé) | | city | string | Ville | | latitude / longitude | number | Origine GPS (tri proximité) | | cart_id | string | Optionnel — poids du panier pour filtrer |

Réponse 200 :

{
  "relayPoints": [
    {
      "id": "71039",
      "code": "71039",
      "name": "TABAC DE LA GARE",
      "address": "12 rue Example",
      "city": "Paris",
      "zipCode": "75001",
      "country": "FR",
      "latitude": 48.86,
      "longitude": 2.34,
      "network": "MONR",
      "distance": 0.4,
      "schedule": ["Lundi - Vendredi : 09:00 – 19:00"],
      "scheduleDetailed": ["Lundi : 09:00 – 12:00, 14:00 – 19:00", "..."]
    }
  ],
  "meta": {
    "totalFound": 12,
    "parcelWeight": 0.5,
    "sortedByProximity": true,
    "searchOrigin": { "latitude": 48.86, "longitude": 2.34, "label": "75001 Paris" }
  }
}

GET /store/boxtal/relay-points/:id

Détail d’un point (id = code parcel point).

Mêmes query optionnels : zipCode, city, cart_id.

Réponse 200 : { "relayPoint": { ... } }

POST /hooks/boxtal

Webhook Boxtal (pas de publishable key). Body JSON + signature HMAC.

POST /admin/orders/:id/boxtal-shipping/sync

Auth admin requise. Force la récupération étiquette / tracking depuis Boxtal.

Réponse :

{
  "order_id": "order_01...",
  "synced": true,
  "results": [{ "fulfillment_id": "ful_...", "synced": true, "label_url": "...", "tracking_number": "..." }]
}

7. Intégration storefront

7.1 Détecter les options Boxtal

Après GET /store/shipping-options?cart_id=... :

function isBoxtalProvider(providerId?: string | null) {
  return !!providerId?.includes("boxtal")
}

function isBoxtalRelayOption(option: {
  provider_id?: string | null
  type?: { code?: string | null }
  data?: { deliveryType?: string }
}) {
  if (!isBoxtalProvider(option.provider_id)) return false
  return (
    option.type?.code === "boxtal-relay" ||
    option.data?.deliveryType === "relay"
  )
}

function isBoxtalHomeOption(option: {
  provider_id?: string | null
  type?: { code?: string | null }
  data?: { deliveryType?: string }
}) {
  if (!isBoxtalProvider(option.provider_id)) return false
  return (
    option.type?.code === "boxtal-home" ||
    option.data?.deliveryType === "home"
  )
}

7.2 Client HTTP (exemple)

const BACKEND = process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL!
const PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!

async function searchRelayPoints(params: {
  zipCode?: string
  city?: string
  latitude?: number
  longitude?: number
  cartId?: string
}) {
  const q = new URLSearchParams()
  if (params.cartId) q.set("cart_id", params.cartId)
  if (params.zipCode) q.set("zipCode", params.zipCode)
  if (params.city) q.set("city", params.city)
  if (params.latitude != null) q.set("latitude", String(params.latitude))
  if (params.longitude != null) q.set("longitude", String(params.longitude))

  const res = await fetch(`${BACKEND}/store/boxtal/relay-points?${q}`, {
    headers: {
      "Content-Type": "application/json",
      "x-publishable-api-key": PUBLISHABLE_KEY,
    },
    cache: "no-store",
  })
  const data = await res.json()
  if (!res.ok) throw new Error(data.message || "Erreur points relais")
  return data as { relayPoints: RelayPoint[]; meta?: unknown }
}

Next.js : vous pouvez proxifier via /api/store/boxtal/... côté app pour éviter d’exposer l’URL backend, ou appeler Medusa directement depuis le serveur.

7.3 Metadata panier (obligatoire)

Avant de finaliser le checkout, stockez le choix dans cart.metadata et dans shipping method data.

Point relais :

const metadata = {
  carrier: "boxtal",
  deliveryType: "relay",
  parcelPointCode: point.code,   // code Boxtal (obligatoire)
  relayPointId: point.code,
  relayPointName: point.name,
  relayPointAddress: `${point.address}, ${point.zipCode} ${point.city}`,
  relayPointNetwork: point.network,
}

Domicile :

const metadata = {
  carrier: "boxtal",
  deliveryType: "home",
}

7.4 Attacher la shipping method

// 1) Mettre à jour le panier
await sdk.store.cart.update(cartId, { metadata: { ...cart.metadata, ...metadata } })

// 2) Sélectionner l’option + data pour validateFulfillmentData
await sdk.store.cart.addShippingMethod(cartId, {
  option_id: shippingOptionId, // id Medusa de l’option boxtal-relay ou boxtal-home
  data: {
    carrier: "boxtal",
    deliveryType: metadata.deliveryType, // "relay" | "home"
    parcelPointCode: metadata.parcelPointCode,
    relayPointId: metadata.relayPointId,
    relayPointName: metadata.relayPointName,
    relayPointAddress: metadata.relayPointAddress,
  },
})

Le provider valide que parcelPointCode / relayPointId est présent pour deliveryType: "relay".

7.5 Flux checkout recommandé

1. Charger shipping options du cart
2. Afficher options Boxtal (relais / domicile)
3. Si relais :
   a. Demander code postal (ou utiliser shipping_address)
   b. GET /store/boxtal/relay-points
   c. L’utilisateur choisit un point
   d. setBoxtalShipping (metadata + shipping method data)
4. Si domicile :
   a. setBoxtalShipping avec deliveryType "home"
5. Continuer paiement → complete cart

7.6 Afficher le point relais après commande

Lire order.metadata ou shipping_methods[0].data :

| Clé | Description | |-----|-------------| | carrier | "boxtal" | | deliveryType | "relay" | "home" | | relayPointName | Nom du point | | relayPointAddress | Adresse formatée | | parcelPointCode / relayPointId | Code Boxtal |

Le subscriber order-placed-boxtal copie ces champs du panier vers la commande.

7.7 Types TypeScript utiles

export type BoxtalRelayPoint = {
  id: string
  code: string
  name: string
  address: string
  city: string
  zipCode: string
  country: string
  latitude?: number
  longitude?: number
  network?: string
  distance?: number
  schedule?: string[] | null
  scheduleDetailed?: string[] | null
}

8. Admin — sync étiquette

Après fulfillment, l’étiquette peut arriver avec quelques secondes de délai.

POST /admin/orders/{order_id}/boxtal-shipping/sync
Authorization: Bearer <admin_token>

Ou script :

npx medusa exec ./src/scripts/sync-boxtal-label.ts order_01...

Données stockées sur le fulfillment (data) :

  • boxtal_order_id
  • boxtal_label_url
  • boxtal_tracking_number
  • boxtal_tracking_url
  • carrier: "boxtal"

9. Comportement à la commande

| Moment | Action | |--------|--------| | order.placed | Copie metadata Boxtal cart → order | | order.placed | Copie poids/dims variante→produit vers metadata lignes | | Création fulfillment | Appel Boxtal createShippingOrder avec colis calculé | | Webhook / sync | Met à jour label + tracking |

Poids : variante → metadata → produit parent (grammes). Min. 0,1 kg.
Dimensions : variante → metadata → produit → défauts env (cm).
Valeur déclarée : somme des lignes (euros) par défaut.

Renseignez product.weight / length / width / height (ou sur chaque variante) dans l’admin.


10. Troubleshooting

| Symptôme | Cause probable | Fix | |----------|----------------|-----| | Options shipping absentes | Setup non exécuté / mauvais provider_id | Relancer setup-boxtal-shipping.ts | | Erreur « point relais manquant » | data.parcelPointCode non passé | Vérifier addShippingMethod data | | Colis 0,1 kg | Poids produit / variante vide | Remplir poids (g) en admin | | Valeur déclarée 1 € | Ancien bug centimes — versions ≥ 0.1.0 corrigées | Utiliser BOXTAL_DECLARED_VALUE_MODE=items | | Pas d’étiquette | Webhook local / délai Boxtal | POST .../boxtal-shipping/sync | | 401 sur Store API | Publishable key manquante | Header x-publishable-api-key |

Scripts de test (repo plugin)

npx medusa exec ./src/scripts/test-boxtal-connection.ts
npx medusa exec ./src/scripts/test-boxtal-package-payload.ts order_xxx
npx medusa exec ./src/scripts/test-boxtal-live-shipment.ts order_xxx

Licence

MIT