
Shopify Delivery Integration Nigeria: API Guide for Relay
Relay Team
If you run a Shopify store in Nigeria and want to pre-position stock across multiple fulfillment centers instead of handling per-order courier dispatches, Relay’s API is the path until a one-click app ships. This guide walks through connecting Shopify to Relay using the public Merchant API — with Node.js code samples, webhook handlers, and checkout quotes. No Silicon Valley jargon, just practical steps for Nigerian merchants and their developers.

Why API-First? (No Shopify App Yet)
Relay doesn’t have a Shopify app today. Integration uses the Merchant API directly. You build a small bridge: when an order is placed on Shopify, a webhook fires and your server calls Relay’s POST /v1/orders endpoint. When Relay updates the delivery status, a signed webhook comes back to update Shopify’s fulfillment state. This is the developer integration path — expect a one-click app in the future, but this works right now.
1. Listen for Shopify Orders (orders/create Webhook)
First, set up a Shopify webhook that fires on orders/create. Your endpoint receives the order payload. Extract the customer address, line items, and order ID. Here’s a basic Node.js handler using Express:
const express = require('express');
const app = express();
app.post('/shopify-order', express.raw({type: 'application/json'}), (req, res) => {
const order = JSON.parse(req.body);
const externalRef = order.id;
// Call Relay API with order data
createRelayOrder(order, externalRef);
res.status(200).send('OK');
});
Notice the externalRef set to order.id. Relay uses this for idempotency — if the webhook retries, it won’t create duplicate orders.

2. Create an Order on Relay (POST /v1/orders)
In your handler, call Relay’s Merchant API. Use your API key (format rlk_...) in the x-api-key header. The order payload needs the customer address, items, and the external reference. Example:
const axios = require('axios');
async function createRelayOrder(order, externalRef) {
const payload = {
external_ref: externalRef,
customer: {
name: order.shipping_address.first_name + ' ' + order.shipping_address.last_name,
phone: order.shipping_address.phone,
address: order.shipping_address.address1 + ', ' + order.shipping_address.city
},
items: order.line_items.map(item => ({
product_external_ref: item.product_id.toString(),
quantity: item.quantity
})),
payment: {
type: order.financial_status === 'paid' ? 'prepaid' : 'cod',
amount_cents: order.total_outstanding * 100 // in kobo
}
};
const response = await axios.post('https://api.relayapp.ng/v1/orders', payload, {
headers: { 'x-api-key': 'rlk_your_api_key_here' }
});
console.log('Relay order created:', response.data.id);
}
Relay’s multi-FC routing kicks in here: if your merchant account has stock pre-positioned at multiple FCs, the system picks the FC closest to the delivery address with available inventory. No manual routing needed.
3. Receive Delivery Status Updates (Relay’s Signed Webhooks)
Relay sends webhooks when the order status changes — picked, packed, out-for-delivery, delivered. The webhook includes an HMAC-SHA256 signature in the x-relay-signature-v2 header. Your endpoint must verify it. Use the signature secret from your Relay dashboard. Here’s a verification snippet:
const crypto = require('crypto');
function verifySignature(req) {
const signature = req.headers['x-relay-signature-v2'];
const timestamp = req.headers['x-relay-timestamp'];
const body = JSON.stringify(req.body);
const expected = crypto
.createHmac('sha256', process.env.RELAY_WEBHOOK_SECRET)
.update(timestamp + body)
.digest('hex');
return signature === expected;
}
When the status is delivered, update Shopify’s fulfillment. Use the Shopify Admin API to mark the order as fulfilled:
const shopify = new Shopify.Clients.Rest(shop, accessToken);
await shopify.post({
path: `orders/${orderId}/fulfillments`,
data: {
fulfillment: { location_id: locationId, tracking_number: relayTrackingPin, status: 'success' }
}
});
Relay returns a tracking PIN — hand that to the customer and note it in Shopify’s fulfillment.
4. Show Multi-FC Quotes at Checkout (POST /v2/quote)
To show delivery costs based on which FC can serve the customer’s address, call Relay’s quote endpoint during checkout. For example, when a customer enters their shipping address, your frontend calls your server, which calls POST /v2/quote. The response lists delivery fees per FC zone. Pick the lowest or display options. Sample request:
const quotePayload = {
delivery_address: { state: 'Lagos', city: 'Ikeja', street: '42 Awolowo Road' },
items: [{ product_external_ref: 'shopify_123', quantity: 1 }]
};
const quote = await axios.post('https://api.relayapp.ng/v2/quote', quotePayload, {
headers: { 'x-api-key': 'rlk_your_api_key' }
});
// quote.data.fees — array of { fc_id, delivery_fee_cents, area_name }
Display the cheapest fee to the customer, or let them choose. This is especially useful for merchants with stock in both Yaba and Surulere FCs — the quote reflects the real cost.
5. Cash on Delivery and Proof of Delivery
Relay captures cash-on-delivery amounts. When the rider delivers, they record pod_amount (expected) and pod_collected (actual). Your webhook receives these fields. For COD orders, you’ll need to reconcile manually — Relay doesn’t automatically flag discrepancies. But the per-delivery data is there. Proof of delivery is a photo and delivery notes, not a signature — pass that to your customer via the tracking page.
Bottom Line
Connecting Shopify to Relay via the Merchant API gives you multi-FC routing, workload-based rider assignment, and realtime status updates — without a one-click app. Until that ships, this Node.js guide shows the exact webhooks and endpoints to use. If you have a developer, replicate these patterns and start shipping with stock pre-positioned at an FC. Get your API key from the Relay dashboard or visit /developers for the full reference.