Shopify

Overview

The ShipRateAPI Shopify app acts as a Carrier Serviceprovider. When a customer reaches checkout, Shopify sends a rate request to the app's callback URL. The app verifies the HMAC signature, forwards the payload to the ShipRateAPI API, and returns the rates back to Shopify — all server-side.

  • Shopify plan with carrier-calculated shipping enabled (required for third-party carrier services)
  • Node.js 18+ runtime for the app server
  • A publicly accessible HTTPS callback URL (use a tunnel such as ngrok for local development)
Environment variables

Copy .env.example to .env and fill in the values:

SHIPRATE_API_ENDPOINT=https://api.shiprateapi.com/api/v1/quotes
SHIPRATE_API_KEY=sk_xxxxxxxxxxxxxxxxxxxx

SHOPIFY_SHARED_SECRET=your_shopify_shared_secret
SHOPIFY_SHOP=your-shop.myshopify.com
SHOPIFY_ACCESS_TOKEN=shpat_xxxx

APP_CALLBACK_URL=https://your-app.example.com/rates
PORT=3010

# Rate label template shown at checkout. Tokens: {Carrier} {Service} (case-insensitive).
RATE_LABEL_FORMAT={Carrier} - {Service}
VariableDescription
SHIPRATE_API_ENDPOINTShipRateAPI quotes endpoint — https://api.shiprateapi.com/api/v1/quotes. Update the version path here without a code change. The app sends X-Platform: shopify automatically.
SHIPRATE_API_KEYYour ShipRateAPI API key for this store
SHOPIFY_SHARED_SECRETFound in your Shopify Partner Dashboard → App → API credentials
SHOPIFY_SHOPYour .myshopify.com domain
SHOPIFY_ACCESS_TOKENAccess token with write_shipping scope
APP_CALLBACK_URLPublic URL Shopify will POST rate requests to (must be HTTPS)
RATE_LABEL_FORMATOptional (default {Carrier} - {Service}). Template for the rate label shown at checkout. Tokens {Carrier} and {Service} are substituted per rate (case-insensitive). Shopify has no carrier-grouping concept, so the carrier is folded into the label.
Installation
npm install
node src/scripts/register.js   # registers the Carrier Service with Shopify
npm start

The register.js script calls the Shopify Admin API to create (or update) the Carrier Service entry pointing at your APP_CALLBACK_URL. Run it once per shop, or again any time the callback URL changes.

Endpoints
EndpointDescription
POST /ratesThe Carrier Service callback. HMAC-verified, then proxied to ShipRateAPI. Always returns 200 — on error it responds with an empty rates array so checkout is never blocked.
GET /healthUnauthenticated health check returning { "status": "ok" }. Useful for load balancers and uptime monitors.
HMAC verification

Every inbound request from Shopify is verified using HMAC-SHA256 before it is processed. The middleware computes the HMAC of the raw request body using your SHOPIFY_SHARED_SECRET and compares it against the X-Shopify-Hmac-Sha256 header. Requests that fail verification receive a 401 response immediately.

Raw body required. HMAC verification must be performed against the raw, unparsed request body. The middleware reads the body as a Buffer before JSON parsing — do not reorder middleware in src/index.js or verification will fail.

Product tags

Native product tags are not used.Shopify does not include a product's Tags field in the Carrier Service rate request, so tagging products in Shopify's product editor has no effect on rating. The app reads tags from line item properties instead.

For each line item the app looks for a property with the key shiprate_tags and treats its value as a comma-separated list. The tags are trimmed and forwarded per line item to the ShipRateAPI API. A line item with no such property is sent with an empty tag list.

"properties": [
  { "key": "shiprate_tags", "value": "fragile, cold-storage" }
]

Line item properties are set when the item is added to the cart — via your product form, the Cart AJAX API, or a Storefront API cart attribute — so tag routing requires storefront work rather than admin configuration. See Tags & Routing for the full list of recognised tags and their routing behaviour.