Getting content ready , please wait...

Warning.

Integration Guide

11 Nov 2026
๐Ÿ“˜ Docs

Integration guide

Connect your shipping system to OneShip: receive shipments and order events in real time, and push delivery status back.

1 How it works

A OneShip integration works in two directions, both scoped to one shipping app:

๐Ÿ“ก OneShip โ†’ Your systemOneShip calls your listener URL when something happens โ€” a shipment is created for your app, its status changes, it is cancelled or returned.
๐Ÿ”„ Your system โ†’ OneShipYour system calls OneShip whenever the shipment moves on your side โ€” picked up, in transit, delivered or returned โ€” so merchants and customers see live tracking.

2 Set up your app

  1. Create a shipping app (Shipping Apps โ†’ Create application).
  2. Open the app โ†’ Coverage, and link the countries and cities you deliver to.
  3. Rates: add a price for each route and weight band.
  4. Events & Webhooks: subscribe your listener URL to the events you need โ€” at least shipment.create.
  5. Keep the Client ID from the app overview for status updates. OneShip activates the app after review.
Open shipping apps โ†’

3 Receive webhooks

Deliveries are HTTP POST requests with a JSON body and these headers:

HeaderMeaning
X-Webhook-SignatureHMAC-SHA256 hex digest of the raw body, keyed with the subscription's signing secret.
X-Webhook-EventThe event code, e.g. shipment.tracked โ€” use it to route the payload and pick the right secret.
X-Webhook-TimestampUnix time of the delivery (sent on queued deliveries).
X-Webhook-IdUnique delivery id โ€” use it to ignore duplicates (sent on queued deliveries).

Example body of a shipment status change:

shipment.tracked ยท body
{
  "shipment_id": 18452,
  "one_ship_number": "OS-2026-000123",
  "status": "transferred",
  "old_status": "prepared",
  "history": {
    "status": "transferred",
    "notes": "Status updated by carrier",
    "event_at": "2026-11-08T10:15:00+03:00"
  }
}
  • Answer with any 2xx status within 10 seconds. Do heavy work asynchronously after acknowledging.
  • Use an https:// listener; payloads contain shipment and customer details.
  • The same event can be delivered more than once (retries). Make your handler idempotent, e.g. by one_ship_number + status.
  • Always read the event type from the X-Webhook-Event header, not from the body.

4 Verify signatures

Never trust a payload before checking its signature. Each event subscription has its own secret (app โ†’ Events & Webhooks โ†’ ๐Ÿ”’). Compute the HMAC of the exact raw body and compare in constant time:

node
const express = require('express');
const crypto = require('crypto');
const app = express();

// one secret per subscribed event ( copy them from the app โ†’ Events & webhooks tab )
const SECRETS = {
  'shipment.create': process.env.ONESHIP_SECRET_SHIPMENT_CREATE,
  'shipment.tracked': process.env.ONESHIP_SECRET_SHIPMENT_TRACKED,
};

// keep the raw body : the signature is computed over the exact bytes received
app.post('/oneship/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const event = req.get('X-Webhook-Event');
  const secret = SECRETS[event];
  if (!secret) return res.sendStatus(400);

  const expected = crypto.createHmac('sha256', secret).update(req.body).digest('hex');
  const received = req.get('X-Webhook-Signature') || '';
  const valid = received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
  if (!valid) return res.sendStatus(401);

  res.sendStatus(200);                 // acknowledge fast โ€ฆ
  handleEvent(event, JSON.parse(req.body)); // โ€ฆ then process asynchronously
});

5 Events catalog

Subscribe per app and per event. Subscriptions can be paused without losing their URL and secret.

EventSent when

6 Send status updates

Push every status change of a OneShip shipment from your system. OneShip validates the transition, updates tracking for the merchant and customer, and notifies subscribers.

Endpoint
POST https://stg.api.oneshipapp.com/api/webhooks/shipment-status-update
AuthenticationX-Client-Id the app Client ID (app โ†’ Overview).
Authorization: Bearer the app token issued by OneShip.
Body (JSON)one_ship_number required โ€” the OneShip shipment number.
status required โ€” the new status (see the mapping below).
external_policy_number optional โ€” your waybill / policy number.
tracking_url optional โ€” public tracking link on your side.
curl
curl -X POST "https://stg.api.oneshipapp.com/api/webhooks/shipment-status-update" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "X-Client-Id: ca_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Authorization: Bearer <APP_TOKEN>" \
  -d '{
    "one_ship_number": "OS-2026-000123",
    "status": "delivered",
    "external_policy_number": "AWB-998877",
    "tracking_url": "https://track.your-company.com/AWB-998877"
  }'

Status mapping

You sendOneShip status
pendingNew (new)
confirmedProcessing (processing)
picked_upIn preparation (in_preparation)
in_transitWith the carrier (transferred)
out_for_deliveryWith the carrier (transferred)
deliveredDelivered (success)
returnedReturned (returned)
failedReturned (returned)
cancelledCancelled (cancelled)

Statuses must move forward through the lifecycle; an invalid jump is rejected with 400. Sending returned for a delivered shipment opens a return shipment (RE-โ€ฆ) automatically.

responses
// 200 โ€” applied
{ "status": true, "message": "Shipment status updated successfully" }

// 400 โ€” rejected ( unknown shipment , shipment of another app , unknown status , invalid transition )
{ "status": false, "message": "Invalid status transition" }

// 401 โ€” missing / wrong X-Client-Id or token
{ "status": false, "message": "Invalid or missing client credentials" }

// 422 โ€” validation ( one_ship_number / status missing )
{ "message": "The status field is required.", "errors": { "status": ["The status field is required."] } }

7 Troubleshooting

  • Webhook Logs shows every delivery with the payload, your response and the duration โ€” start there.
  • Signature mismatch: hash the raw body (not re-serialised JSON) and use the secret of that event's subscription.
  • Timeouts: acknowledge first, then process; deliveries are cut after 10 seconds.
  • No deliveries: check the subscription is active and the app is activated by OneShip.
  • 401 on status updates: check the X-Client-Id header and the Bearer token belong to the same app.
๐Ÿ“œ Webhook Logs
All rights reserved BOITC - BeOne Information Technology 2026 ยฉ