Skip to main content

Overview

The ShipBob Orders API enables you to programmatically create orders, retrieve tracking information, and manage fulfillment. This guide walks you through building a complete orders integration.

How It Works

Here’s the complete order lifecycle from creation to delivery tracking:

Requirements

Before you begin, ensure:
  • Your API key has the orders_write and orders_read access scopes
  • You have your ShipBob channel ID (get it here)

Step 1: Create an Order

Use the Create Order endpoint to create an order.
Make sure to pass the shipbob_channel_id in the request header. This identifies which channel the order belongs to.
POST https://{env}.shipbob.com/{api_version}/order
{
  "shipping_method": "Standard",
  "recipient": {
    "name": "John Doe",
    "address": {
      "address1": "100 N Racine Ave",
      "address2": "Suite 100",
      "company_name": null,
      "city": "Chicago",
      "state": "IL",
      "country": "US",
      "zip_code": "60607"
    },
    "email": "[email protected]",
    "phone_number": "555-555-5555"
  },
  "products": [
    {
      "name": "Light Roast Coffee",
      "reference_id": "LIGHT-ROAST",
      "quantity": 1
    }
  ],
  "reference_id": "1234762738908",
  "order_number": "1001",
  "type": "DTC",
  "tags": [
    {
      "name": "Subscription Order",
      "value": "0"
    },
    {
      "name": "New Customer",
      "value": "0"
    }
  ]
}
What you’ll get back: The response returns information about the order and associated shipments, including the shipment IDs, line items, and the assigned fulfillment center.
JSON response
{
  "id": 309589638,
  "created_date": "2025-11-19T00:06:43.7807166+00:00",
  "purchase_date": null,
  "reference_id": "1234762738908",
  "order_number": "1001",
  "status": "ImportReview",
  "type": "DTC",
  "channel": {
    "id": 432951,
    "name": "PAT Channel"
  },
  "shipping_method": "Standard",
  "recipient": {
    "name": "John Doe",
    "address": {
      "address1": "100 N Racine Ave",
      "address2": "Suite 100",
      "city": "Chicago",
      "state": "IL",
      "country": "US",
      "zip_code": "60607"
    },
    "email": "[email protected]",
    "phone_number": "555-555-5555"
  },
  "products": [
    {
      "id": 1377083100,
      "reference_id": "LIGHT-ROAST",
      "quantity": 1,
      "quantity_unit_of_measure_code": "EA",
      "sku": "LIGHT-ROAST",
      "gtin": "",
      "upc": "",
      "unit_price": null,
      "external_line_id": null
    }
  ],
  "tags": [
    {
      "name": "Subscription Order",
      "value": "0"
    },
    {
      "name": "New Customer",
      "value": "0"
    }
  ],
  "shipments": [
    {
      "id": 317255024,
      "order_id": 309589638,
      "reference_id": "1234762738908",
      "recipient": {
        "name": "John Doe",
        "full_name": "John Doe",
        "address": {
          "address1": "100 N Racine Ave",
          "address2": "Suite 100",
          "company_name": null,
          "city": "Chicago",
          "state": "IL",
          "country": "US",
          "zip_code": "60607"
        },
        "email": "[email protected]",
        "phone_number": "555-555-5555"
      },
      "created_date": "2025-11-19T00:06:43.7807166+00:00",
      "last_update_at": null,
      "last_tracking_update_at": null,
      "status": "ImportReview",
      "status_details": [],
      "location": null,
      "invoice_amount": 0.0,
      "invoice_currency_code": null,
      "insurance_value": null,
      "ship_option": "Ground",
      "tracking": null,
      "products": [
        {
          "id": 1377083100,
          "reference_id": "LIGHT-ROAST",
          "name": "Light Roast Coffee",
          "sku": "LIGHT-ROAST",
          "inventory_items": [
            {
              "id": 21756231,
              "name": "Light Roast Coffee",
              "quantity": 1
            }
          ]
        }
      ]
      // ... additional shipment fields omitted for brevity
    }
  ]
  // ... additional fields omitted for brevity
}
The reference_id field is your idempotency key. If ShipBob receives two identical requests with the same reference_id + shipbob_channel_id, it will return a 422 error.

Step 2: Retrieve Tracking Details

ShipBob offers two workflows for retrieving shipment details:

Webhooks

Real time updates via webhooks. Click to jump to this section.

Polling

Poll the API for updates on a schedule. Click to jump to this section.

Webhooks

ShipBob can fire webhooks for shipment events including:
  • Shipped - When a shipment leaves the warehouse
  • Delivered - When the carrier confirms delivery
  • Exception - Product out of stock or other fulfillment issues
  • On Hold - Invalid address or payment issues
  • Cancelled - Shipment was cancelled
How to subscribe:
  1. Via Dashboard: Go to Integrations > Webhooks > Add Subscription Create webhook subscription
  2. Via API: Use the Create Webhook Subscription endpoint
Learn more in the Webhooks documentation.
ShipBob uses exponential backoff to retry webhook delivery for up to 24 hours, but cannot guarantee events arrive in the original sequence. Always check timestamps when processing webhooks.

Polling

Poll the GET Orders endpoint on a recurring schedule (every 15-30 minutes). Key parameters:
  • HasTracking - Filter for orders where tracking is available (shipment has been labeled)
  • IsTrackingUploaded - Use as a sync flag. Set to false to find unsynced orders
Workflow:
Pass the shipbob_channel_id header to only retrieve orders from your integration channel, avoiding data from other integrations the merchant may have installed.
Understanding split shipments: An order can have multiple shipments if:
  • Inventory is stocked in multiple fulfillment centers
  • Items don’t fit in one box due to size/weight
When a shipment has tracking, its status will be LabeledCreated, which quickly transitions to Completed. Always loop through the shipments[] array in the order response. Example: Order with split shipments
{
  "id": 123456,
  "reference_id": "ORDER-001",
  "status": "Partially Fulfilled",
  "shipments": [
    {
      "id": 789101,
      "status": "Completed",
      "tracking": {
        "number": "1Z999AA10123456784",
        "carrier": "UPS"
      },
      "products": [
        { "reference_id": "SKU-A", "quantity": 1 }
      ]
    },
    {
      "id": 789102,
      "status": "Processing",
      "tracking": null,
      "products": [
        { "reference_id": "SKU-B", "quantity": 2 }
      ]
    }
  ]
}
For complete order and shipment status details, see the Status Reference.

Step 3: Mark Tracking as Synced

After syncing tracking to your system, mark shipments as uploaded to prevent re-processing:
POST https://{env}.shipbob.com/{api_version}/shipment:batchUpdateTrackingUpload

{
  "shipment_ids": [789101, 789102],
  "is_tracking_uploaded": true
}
This updates the IsTrackingUploaded flag so future queries with IsTrackingUploaded=false won’t return these shipments.

Retrieve Orders and Shipments

Get a specific order:
GET https://{env}.shipbob.com/{api_version}/order/{id}
Get a specific shipment:
GET https://{env}.shipbob.com/{api_version}/shipment/{id}
When looking at the order response payload, the shipment id is in the shipments array.

Search for Orders

Use query parameters on the GET Orders endpoint to search for orders. Common search queries:
Use CaseQuery Example
Orders with tracking informationorder?HasTracking=true&IsTrackingUploaded=false
Search by reference IDorder?ReferenceIds=1234762738908
Orders within a date rangeorder?StartDate=2025-11-01&EndDate=2025-11-30
Example: Get orders with tracking that haven’t been synced:
GET https://{env}.shipbob.com/{api_version}/order?HasTracking=true&IsTrackingUploaded=false&Limit=250&Page=1
Example: Search by reference_id:
GET https://{env}.shipbob.com/{api_version}/order?ReferenceIds=1234762738908
Example: Get all orders for November 2025:
GET https://{env}.shipbob.com/{api_version}/order?StartDate=2025-11-01&EndDate=2025-11-30

Important Fields

reference_id - Your unique order identifier. Acts as an idempotency key—duplicate reference_id + shipbob_channel_id combinations return a 422 error. order_number - User-friendly order number for customer service. Does not need to be unique (can match reference_id). shipping_method - Value like “Standard”, “Expedited”, or “2-Day”. Merchants map this to ShipBob Ship Options that determine SLA and carrier selection. See Ship Options guide. type - Order type:
  • DTC - Direct-to-consumer orders (most common)
  • B2B - Business-to-business orders (see B2B Orders guide)
shipbob_channel_id (header) - Identifies which channel the order belongs to. Get your channel ID from the GET Channels endpoint. products.reference_id - SKU or unique product identifier. Must match a product created in ShipBob (see Product Management Guide). IsTrackingUploaded - Boolean flag indicating if you’ve synced the tracking to your system. Use this to prevent duplicate processing.

Common Issues

Each order must have a unique reference_id within a channel. If you need to resubmit, use a different reference_id or cancel the original order first.
Ensure required fields are provided: address1, city, country (ISO Alpha-2 code), and ideally state and zip_code.
Call the GET Channels endpoint. Look for the channel with _write scopes—that’s your integration channel.
Check the status_details field in the shipment for specific reasons. Common causes: out of stock, invalid address, missing customs info. See Status Reference for details.

Tips

  • Poll every 15-30 minutes - Don’t check more frequently than every 5 minutes to avoid rate limits
  • API rate limit - 150 requests per minute
  • Always use shipbob_channel_id header - Prevents retrieving orders from other integrations
  • Use webhooks + polling fallback - Webhooks for real-time updates, polling as a safety net
  • Handle split shipments - Always loop through order.shipments[] and sync each tracking number separately
  • Mark tracking as uploaded - Use the batchUpdateTrackingUpload endpoint to avoid re-processing