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-shiprocket-fulfillment-sbl

v0.0.24

Published

Shiprocket Fulfillment Provider Plugin for MedusaJS 2

Readme

🚀 Overview

The Medusa Shiprocket Fulfillment Plugin integrates Shiprocket, India's leading logistics aggregator, directly into your Medusa store.

Streamline your shipping operations by automating rate calculations, order creation, label generation, and returns—all from within the Medusa Admin.

Compatible with Medusa v2.0+

✨ Key Features

| Feature | Description | | :--- | :--- | | 💵 Automated Rates | Fetch real-time shipping rates at checkout based on pickup and delivery pin codes. Automatically selects the cheapest available courier. | | 📦 Seamless Fulfillment | Automatically create shipments in Shiprocket when you fulfill an order in Medusa. Includes automatic AWB (Air Waybill) assignment. | | 📄 Document Generation | Automatically generate and retrieve Shipping Labels, Manifests, and Invoices directly from Shiprocket. Documents are accessible via the admin widget. | | 🖥️ Admin Widget | Beautiful admin widget on order details page showing shipment status, tracking info, and quick access to labels, manifests, and invoices. | | ↩️ Returns Management | Handle return requests and generate reverse pickup shipments effortlessly with dedicated return fulfillment support. | | 🔍 Serviceability & ETD | GET /store/shiprocket/serviceability checks pincode serviceability and EDD using the variant’s weight/dimensions and pickup from Medusa stock location addresses (inventory levels), with optional pickup_pincode override—no cart required. | | 🛑 Easy Cancellation | Cancel shipments instantly from the Medusa Admin to void labels and prevent unnecessary charges. | | 🔐 Auto Token Refresh | Scheduled job automatically refreshes Shiprocket authentication tokens every 8 days to ensure uninterrupted service. | | 📊 Tracking Support | Built-in tracking number and tracking URL integration for real-time shipment status updates. | | 🔔 Status Webhook | Optional webhook for Shiprocket to notify when an order is shipped or delivered; automatically creates shipment or marks fulfillment as delivered in Medusa. | | 🧾 Tracking event stream | Optional shipment_tracking module (bundled with this plugin) stores Shiprocket scan history (append-only, deduped); webhook ingest and admin APIs use it and emit shipment.tracking.updated when the latest normalized milestone changes. | | 🇮🇳 India-First | Optimized for Indian addresses, GST compliance, HSN codes, and domestic courier networks. |

📋 Prerequisites

Before you begin, ensure you have:

  1. A Medusa v2 server set up.
  2. A Shiprocket account.
  3. At least one Pickup Location (nickname) in your Shiprocket dashboard—used when creating shipments from Medusa fulfillments (must match pickup_location / SHIPROCKET_PICKUP_LOCATION in the fulfillment provider modules config).
  4. For checkout rates and store serviceability, Stock locations in Medusa need a valid address with postal code, and variants need inventory with location levels linked to those locations (see Product Requirements).

🛠️ Installation

Install the plugin using your preferred package manager:

npm install medusa-shiprocket-fulfillment-sbl
# or
yarn add medusa-shiprocket-fulfillment-sbl

⚙️ Configuration

1. Environment Variables

Add your Shiprocket credentials to your .env file.

[!WARNING] Security Note: Never commit your actual API passwords to version control (git).

SHIPROCKET_EMAIL="[email protected]"
SHIPROCKET_PASSWORD="your_shiprocket_password"
# Must match the 'Nickname' of a pickup location in your Shiprocket dashboard (fulfillment / order creation).
SHIPROCKET_PICKUP_LOCATION="Primary"

2. Medusa Config

Register the plugin in your medusa-config.js (or medusa-config.ts) file. You need to add it to the modules section for the fulfillment provider.

module.exports = defineConfig({
  // ... other config
  modules: [
    {
      resolve: "@medusajs/medusa/fulfillment",
      options: {
        providers: [
          {
            resolve: "medusa-shiprocket-fulfillment-sbl",
            id: "shiprocket",
            options: {
              email: process.env.SHIPROCKET_EMAIL,
              password: process.env.SHIPROCKET_PASSWORD,
              pickup_location: process.env.SHIPROCKET_PICKUP_LOCATION || "Primary",
              /**
               * Cash on Delivery support.
               * Accepts: 0, 1, "true", or "false"
               * Set to 1 or "true" to enable COD for rate calculations.
               */
              cod: "false", 
            },
          },
        ],
      },
    },
  ],
  plugins: [
    {
      resolve: "medusa-shiprocket-fulfillment-sbl",
      options: {
        // Required Shiprocket configuration
        shiprocket: {
          email: process.env.SHIPROCKET_EMAIL,
          password: process.env.SHIPROCKET_PASSWORD,
        },
      },
    },
  ],
});

Required Plugin Options:

  • shiprocket.email - Your Shiprocket account email (required)
  • shiprocket.password - Your Shiprocket account password (required)
  • shiprocket.pickupLocation (optional) — Shiprocket warehouse nickname; defaults to "Primary" if omitted. Used where the plugin talks to Shiprocket with a warehouse name (e.g. admin document flows); the fulfillment provider uses pickup_location in the modules config above.

Optional (for webhook):

  • webhookSecret - Shared secret for Shiprocket status webhook. If set, Shiprocket can notify your store when an order is shipped or delivered. Use POST /carrier-tracking/webhook in Shiprocket’s dashboard.
  • publishableKey - Medusa publishable API key (optional). Resolved in the webhook handler if you add extra checks; not required for POST /carrier-tracking/webhook.

[!NOTE] The admin widget is automatically included when the plugin is installed. No additional plugin registration is required for the admin UI.

3. Automatic Token Refresh

The plugin includes a scheduled job that automatically refreshes Shiprocket authentication tokens every 8 days to ensure uninterrupted service. This job runs automatically and requires no configuration.

  • Schedule: Every 8 days at 00:00 (midnight)
  • Job Name: refresh-shiprocket-token
  • Automatic: No manual intervention required

The plugin also handles token refresh automatically when API requests receive 401 Unauthorized responses, ensuring seamless operation even if the scheduled job is delayed.

🖥️ Admin Widget

The plugin includes a built-in admin widget that appears on the order details page, providing quick access to Shiprocket documents and shipment information.

Features

  • Shipment Status Display: Shows the current status of each active shipment (Delivered, Pending, Cancelled) with color-coded badges
  • Quick Document Access: Direct links to download:
    • Shipping Label: Print-ready shipping label for the shipment
    • Manifest: Shipping manifest document
    • Invoice: Order invoice from Shiprocket
  • Tracking Information: Displays Shipment ID and tracking details

Location

The widget automatically appears in the Order Details page sidebar (order.details.side.after zone) for orders with active Shiprocket fulfillments.

[!NOTE] The widget only displays for fulfillments that have been successfully created in Shiprocket (with AWB and shipment_id). Cancelled or failed fulfillments are not shown.

🌐 Storefront API

The plugin provides a custom storefront endpoint for quick pre-checkout serviceability and delivery estimates.

Check Serviceability

GET /store/shiprocket/serviceability

Use this endpoint on product pages or in the cart to check if a pincode is serviceable and get estimated delivery dates.

  • Dimensions & weight come from the variant (Medusa: weight in grams, length/width/height in cm).
  • Pickup postcode is chosen from inventory location levelsstock locationaddress.postal_code (same idea as checkout pickup from stock).
  • pickup_pincode (optional query param) overrides the above for testing or special cases.

Query Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :--- | :--- | | pincode | string | Yes | The delivery pincode to check. | | variant_id | string | Yes | Product variant id. Must have weight (g), length, width, and height (cm) set. | | pickup_pincode | string | No | Overrides pickup postcode (skips stock location resolution). | | cod | integer | No | 1 for COD, 0 for Prepaid. Defaults to 0. | | declared_value | integer | No | Declared shipment value in INR. | | order_id | integer | No | Existing Shiprocket order id, if applicable. |

Example Request

Store routes typically require Medusa’s publishable key header (adjust host and keys for your project):

curl -X GET "http://localhost:9000/store/shiprocket/serviceability?pincode=110001&variant_id=variant_01HQWE..." \
  -H "x-publishable-api-key: YOUR_PUBLISHABLE_KEY"

Optional: &pickup_pincode=560001 to force a pickup pincode instead of resolving it from stock locations.

Example Response

{
  "status": 200,
  "data": {
    "available_courier_companies": [
      {
        "id": 1,
        "courier_name": "Delhivery",
        "rate": "120.00",
        "etd": "2026-01-15",
        "estimated_delivery_days": 3
      }
    ]
  }
}

Shiprocket Status Webhook

| Endpoint | Use case | | :--- | :--- | | POST /carrier-tracking/webhook | Shiprocket dashboard URL — Medusa does not require x-publishable-api-key here. Path avoids Shiprocket’s banned substrings (shiprocket, kartrocket, sr, kr). |

Allows Shiprocket to notify your store when an order is shipped or delivered. The plugin then automatically updates the Medusa order (creates shipment or marks fulfillment as delivered), so you no longer need to do this manually in the admin.

Configuration

  1. Webhook secret: In plugin options, set webhookSecret (e.g. from process.env.SHIPROCKET_WEBHOOK_SECRET). If not set, the webhook responds with 501 and does not process requests.
  2. Publishable key (optional): Set publishableKey in plugin options only if you extend the handler to validate it; Shiprocket does not send this header.
  3. Shiprocket dashboard: In Shiprocket, go to Settings → Additional Settings → Webhooks. Enable the webhook, set URL to https://your-medusa-backend.com/carrier-tracking/webhook, and set Token to the same value as your webhookSecret. Shiprocket sends the Token in the x-api-key HTTP header.
  4. Authentication: The plugin accepts the secret via any of:
    • Header: X-Api-Key: <webhookSecret> (used by Shiprocket when you set the Token in their dashboard)
    • Header: Authorization: Bearer <webhookSecret>
    • Header: X-Shiprocket-Secret: <webhookSecret>
    • Query: ?secret=<webhookSecret> (less secure; use only if Shiprocket cannot send headers)

Example plugin config (with webhook)

plugins: [
  {
    resolve: "medusa-shiprocket-fulfillment-sbl",
    options: {
      shiprocket: {
        email: process.env.SHIPROCKET_EMAIL,
        password: process.env.SHIPROCKET_PASSWORD,
      },
      webhookSecret: process.env.SHIPROCKET_WEBHOOK_SECRET,
      publishableKey: process.env.MEDUSA_PUBLISHABLE_KEY,
    },
  },
],

Expected webhook body (Shiprocket)

The handler accepts a flexible JSON body. Typical fields:

| Field | Type | Description | | :--- | :--- | :--- | | order_id | string/number | Shiprocket order id | | shipment_id | string/number | Shiprocket shipment id | | channel_order_id | string | Medusa order id (order_...) or numeric display_id (e.g. 1001); the plugin sends display_id to Shiprocket when present so the dashboard shows a short order number | | status, shipment_status, or current_status | string | e.g. "shipped", "Delivered" (normalized in code) | | tracking_number, tracking_url, awb_code | string | Optional; used when creating the shipment | | awb | number/string | AWB / tracking; used for lookup and labels. If it matches fulfillment.data, a Manual fulfillment can still be matched |

At least one of order_id, shipment_id, awb, or channel_order_id is required. Status is read from status, then shipment_status, then current_status. Values like "shipped", "delivered", "Delivered", "dispatch", "delivery" are normalized automatically.

When the status is delivered and Medusa has not shipped the fulfillment yet, the handler runs create shipment (admin “Mark as shipped”) using AWB/URLs from the payload, then mark as delivered (“Mark as delivered”).

Shiprocket may send additional fields (e.g. scans, current_timestamp, etd, channel, courier_name); these are accepted. When the shipment_tracking module is registered (see below), webhook payloads with scans (or a normalizable top-level status) are ingested into an append-only event table with deduplication (dedupe_hash from AWB + normalized activity + event time). Ingestion failures are logged; the handler still tends to respond 200 so Shiprocket does not retry aggressively.

Fulfillment timestamps: Medusa core Fulfillment does not expose packed_at in all versions. Packed milestones are represented in the tracking stream (and customer timeline), not written to a core packed_at field unless you add your own metadata convention.

The exact payload from Shiprocket may differ; confirm from Shiprocket’s dashboard or docs and adjust the parser if needed.

Query parameters

| Parameter | Type | Default | Description | | :--- | :--- | :--- | :--- | | shiprocket_only | string | true | When true or omitted, only Shiprocket provider fulfillments are matched unless the payload AWB matches fulfillment.data (so Manual fulfillments with stored AWB can still match). When false, any fulfillment matching ids/AWB is used. |

Example request

curl -X POST "http://localhost:9000/carrier-tracking/webhook" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_WEBHOOK_SECRET" \
  -d '{"order_id": "12345", "shipment_id": "67890", "status": "delivered"}'

Responses

  • 200: Status processed (shipment created and/or marked delivered), ignored (e.g. status not shipped/delivered), idempotent (already shipped/delivered), or no fulfillment matched (dummy test ids — still 200).
  • 400: Invalid body (e.g. missing identifiers or invalid shape).
  • 401: Missing or invalid webhook secret.
  • 501: Webhook not configured (no webhookSecret in plugin options).

Shipment tracking module (optional)

Register the shipment_tracking module from this package (migration and service live under medusa-shiprocket-fulfillment-sbl/modules/shipment-tracking). No separate plugin is required.

module.exports = defineConfig({
  // ...
  modules: [
    // ...existing modules
    {
      resolve: "medusa-shiprocket-fulfillment-sbl/modules/shipment-tracking",
    },
  ],
});

After upgrading, run DB migrations (same as your Medusa workflow: npx medusa db:migrate or plugin migration command) so table shipment_tracking_event exists.

Do not register this module twice (for example alongside order-management/modules/shipment-tracking) — both use the same module key shipment_tracking and the same table.

Identifiers: Webhook order_id / shipment_id are Shiprocket-side ids. channel_order_id echoes what you sent at create time: numeric Medusa display_id (preferred for a short Shiprocket UI label) or internal id (order_...). The webhook resolves both. awb (or awb_code / tracking_number) ties scans to fulfillment lookup and dedupe hashing.

Deduping: Each scan row is keyed by dedupe_hash (SHA-256 of AWB + normalized activity text + raw event time string). Replays of the same scan do not insert duplicate rows.

Internal event: When ingestion changes the latest normalized milestone for a fulfillment, the webhook emits shipment.tracking.updated on the Medusa event bus with payload shape:

{
  "order_id": "order_...",
  "fulfillment_id": "ful_...",
  "latest_normalized": "delivered",
  "previous_normalized": "in_transit"
}

Read APIs

| Scope | Method | Path | Notes | | :--- | :--- | :--- | :--- | | Store | GET | /store/orders/:order_id/shipment-timeline | Not part of this package. You can expose timeline data with a custom route using shipment_tracking, or use order-management if you already depend on it. | | Admin | GET | /admin/orders/:id/shipment-tracking-events | Full rows including raw_payload (admin auth). |

If the module is not registered, webhook tracking ingest and GET /admin/orders/:id/shipment-tracking-events respond 501 with a hint to add the module.

[!NOTE] The public webhook path remains POST /carrier-tracking/webhook (not /webhooks/shiprocket) so Shiprocket’s URL validation accepts it.

💻 Usage Guide

Enabling the Provider

  1. Log in to your Medusa Admin.
  2. Go to SettingsRegions.
  3. Select the region you want to ship to (e.g., "India").
  4. In the Fulfillment Providers section, edit and ensure shiprocket is selected.
  5. Save changes.

Shipping Options

You can now create Shipping Options (e.g., "Standard Shipping") that use the shiprocket provider.

  • Calculated: Choose "Calculated" price type to use Shiprocket's real-time rate API, which automatically selects the cheapest available courier.

Product Requirements

For successful fulfillment creation, ensure your product variants have the following properties set:

  • Weight (in grams): Required for rate calculation and shipment creation
  • Length (in cm): Required for shipment creation
  • Width (in cm): Required for shipment creation
  • Height (in cm): Required for shipment creation
  • HSN Code: Optional but recommended for GST compliance

For GET /store/shiprocket/serviceability (in addition to the dimensions above):

  • The variant must have inventory linked (Manage inventory in Admin when applicable) with at least one inventory level on a stock location whose address includes a postal code (Indian pincode). The endpoint picks a level preferring positive available quantity, then highest quantity; if none have stock, any level with a postal code is used.
  • If the variant cannot resolve a pickup postcode, pass pickup_pincode on the query string or fix stock location / inventory in Admin.

[!WARNING] Missing dimensions or weight will cause fulfillment creation to fail with an error. Ensure all product variants have these values configured in the Medusa Admin.

Creating a Fulfillment (Shipment)

When you fulfill an order in the Medusa Admin:

  1. The plugin creates an order in Shiprocket with all required shipping and billing information. It sends Medusa display_id as order_id and channel_order_id when the order has a positive numeric display id (short label in Shiprocket); otherwise it falls back to the internal order_... id. Webhooks match either form.
  2. It automatically assigns an AWB (Air Waybill) using Shiprocket's "adhoc" API.
  3. If successful, the Tracking Number and Tracking URL are saved to the fulfillment in Medusa.
  4. Documents are automatically generated: Shipping label, manifest, and invoice are created and linked to the fulfillment.
  5. The Admin Widget on the order details page will display the shipment status and provide quick access to all documents.

Viewing Shipment Documents

After fulfillment creation, you can access documents in two ways:

  1. Admin Widget (Recommended): Navigate to the order details page in Medusa Admin. The Shiprocket Printables widget in the sidebar shows direct links to Label, Manifest, and Invoice.
  2. Fulfillment Data: Documents URLs are stored in the fulfillment's labels property and can be accessed programmatically.

🐛 Troubleshooting

Store serviceability (GET /store/shiprocket/serviceability)

  • Missing inventory / stock location data: Ensure the variant has inventory levels tied to a stock location with a postal code on the address (see Product Requirements).
  • Missing variant dimensions: Set weight (grams) and length, width, height (cm) on the variant; the endpoint returns 400 if they are missing or invalid.
  • Bypass pickup resolution: Add pickup_pincode to the query string when you only need a quick Shiprocket check against a known warehouse pincode.

Rate Calculation Issues

"Both pickup and delivery postcodes are required for rate calculation"

  • Ensure your Stock Location has a valid address with a 6-digit Indian postal code configured.
  • Verify the customer's shipping address has a valid 6-digit Indian postal code.
  • The pickup postcode comes from your Stock Location address linked to the Sales Channel.

"No couriers available for this route"

  • The route between pickup and delivery pincodes may not be serviceable by any courier.
  • Verify both pincodes are valid and serviceable in Shiprocket's network.
  • Check if there are any serviceability restrictions in your Shiprocket dashboard.

"Rate calculation failed unexpectedly"

  • Check that product variants have weight set (in grams). If weight is missing, the plugin defaults to 0.5kg, but this may cause issues.
  • Verify network connectivity to Shiprocket API.
  • Check plugin logs for detailed error messages.

Fulfillment Creation Issues

"Missing dimensions/weight for item [item name]. Please update product variant settings."

  • Required: Each product variant must have:
    • weight (in grams)
    • length (in cm)
    • width (in cm)
    • height (in cm)
  • Update product variants in Medusa Admin → Products → [Product] → Variants → Edit
  • All dimensions are required for Shiprocket to create the shipment.

"Failed to create Shiprocket order: No shipment ID returned"

  • This indicates Shiprocket API returned an unexpected response.
  • Check Shiprocket dashboard for any account restrictions or issues.
  • Verify all required order data is present (billing/shipping addresses, items, etc.).

"AWB assignment failed"

  • The order was created but AWB assignment failed. The plugin attempts to cancel the order automatically.
  • Check Shiprocket dashboard for courier availability issues.
  • Verify your Shiprocket pickup location (nickname / SHIPROCKET_PICKUP_LOCATION) is active and correctly configured.

"Shiprocket Error: [error message]"

  • This is a direct error from Shiprocket API. The message will indicate the specific issue.
  • Common causes:
    • Invalid address data
    • Missing required fields
    • Account restrictions
    • API rate limits

Authentication Issues

"Shiprocket API credentials are required"

  • Ensure SHIPROCKET_EMAIL and SHIPROCKET_PASSWORD are set in your .env file.
  • Verify credentials are correct and your Shiprocket account is active.

Token Refresh Failures

  • The plugin automatically refreshes tokens every 8 days via a scheduled job.
  • If authentication fails, check:
    • Credentials are still valid
    • Account is not suspended
    • Network connectivity to Shiprocket API

Pickup Location Issues

"Pickup location not found" (Shiprocket order / fulfillment)

This applies when creating a shipment in Shiprocket using the warehouse nickname from your fulfillment provider config (pickup_location / SHIPROCKET_PICKUP_LOCATION).

  • Ensure that value matches the exact Nickname of a pickup location in your Shiprocket dashboard.
  • The pickup location must be active and properly configured in Shiprocket.
  • Default value is "Primary" if not specified.

Store GET /store/shiprocket/serviceability — pickup postcode

  • Default pickup comes from Medusa: variant inventorylocation levelsstock locationaddress.postal_code.
  • Errors about no inventory linked or no postal code: enable/link inventory for the variant, ensure location levels exist, and set the stock location address in Medusa Admin—or pass pickup_pincode on the request.

Admin Widget Not Showing

  • The widget only appears for fulfillments with:
    • awb (Air Waybill) assigned
    • shipment_id present
    • Provider ID is shiprocket
    • Fulfillment is not cancelled
  • If documents are missing, the fulfillment may have been created but document generation failed. Check fulfillment data for error messages.

🤝 Contributing

Contributions are welcome! If you find a bug or want to add a feature:

  1. Fork the repository.
  2. Create a feature branch (git checkout -b feature/amazing-feature).
  3. Commit your changes.
  4. Open a Pull Request.

📄 License

This project is licensed under the MIT License.