Systems
ShipBob integration with your store and ERP: orders to the warehouse, stock and tracking back
ShipBob allows 150 API requests a minute per user and application, rejects a second order with the same reference_id, and reports several stock numbers of which only one can ship today. We build the integration between ShipBob, your store and your ERP on those rules, then host and run it.
What ShipBob is and who runs it
ShipBob is a fulfillment and storage provider for e-commerce merchants: a third-party logistics company (3PL) with its own network of fulfillment centers. A merchant sends stock in, ShipBob stores it, picks and packs orders and ships them. The integration question is how orders get to ShipBob, and how stock, tracking and returns get back to the store and the ERP.
ShipBob's API has dated versions since July 2025. A new version comes every six months, in January and July, and each is supported for 24 months.
| Version | Released | End of support |
|---|---|---|
| 1.0 and 2.0 | before July 2025 | 31 July 2026; 1.0 returns 410 Gone from 29 August 2026 |
| 2025-07 | 31 July 2025 | 31 July 2027 |
| 2026-01 | 31 January 2026 | 31 January 2028 |
| 2026-07 | 31 July 2026 | 31 July 2028 |
An integration built today runs on https://api.shipbob.com/2026-07/ and needs one version step every two years at least.
What connects to ShipBob
The store owns the order. ShipBob owns what is physically in its fulfillment centers. The ERP owns item master data and purchasing.
| Flow | Direction | ShipBob resource |
|---|---|---|
| Orders | store to ShipBob | POST /order with reference_id and shipping_method |
| Products | ERP or store to ShipBob | /product, reference_id is the SKU |
| Stock | ShipBob to store and ERP | GET /inventory-level |
| Shipments and tracking | ShipBob to store | webhooks order.shipped, order.shipment.tracking.updated |
| Inbound stock | ERP to ShipBob | warehouse receiving order (WRO) |
| Returns | store to ShipBob and back | /return, webhooks return.created, return.completed |
A WRO is ShipBob's version of an advance ship notice: the ERP's purchase order becomes a receiving order, and the wro.box.stowed webhook tells the integration when the stock is on the shelf.
How ShipBob exposes data
Authentication and channels
ShipBob accepts a Personal Access Token or OAuth 2.0, both as a bearer token. A Personal Access Token does not expire and has full account access. OAuth gives an access token valid for 1 hour and a refresh token valid for 30 days, renewed on every refresh, with scopes such as orders_write and inventory_read. Every write carries a shipbob_channel_id header. A channel is one installation of an application, and an application can read data from all of the merchant's channels but writes only to its own.
150 requests a minute
ShipBob limits calls to 150 a minute in a sliding window, counted per user and per application across all ShipBob APIs. Over the limit it answers 429 and says how long to wait:
HTTP/1.1 429 Too Many Requests
x-retry-after: 25
x-remaining-calls: 0
{"statusCode":429,"message":"Rate limit is exceeded. Try again in 25 seconds."}
Worked through for a sale day with 3,000 orders: one POST /order each is 3,000 calls, which at 150 a minute is 20 minutes of the full budget. Reading tracking back per order would cost another 3,000 calls and another 20 minutes. With the order.shipped webhook it costs none, and the budget stays for orders, stock and retries. The API throttling and backoff note covers the retry side.
Webhooks
Webhooks are signed with HMAC SHA-256 over webhook-id, webhook-timestamp and the raw body, and the receiver must answer 2xx within 15 seconds. A failed message is retried immediately, then after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours, each period counted from the previous failure. The last attempt comes 27 hours 35 minutes 5 seconds after the first. After that the message is marked failed, and an endpoint that fails for 5 days is disabled. The webhook-id stays the same on a resend, so the integration stores it and drops a message it has already processed. More in webhooks are not a guarantee.
Where a ShipBob integration gets stuck
Which stock number
The inventory-level endpoint returns a set of totals per inventory item: total_on_hand_quantity, total_committed_quantity, total_fulfillable_quantity (on hand minus committed), total_awaiting_quantity, total_backordered_quantity and total_sellable_quantity. Its field reference defines sellable as fulfillable plus awaiting minus quarantine minus damaged. ShipBob's concepts page defines it as fulfillable minus exception orders. The two definitions differ, and the first includes stock that has not arrived.
The integration sends total_fulfillable_quantity to the store, per SKU, with a buffer where you want one. The which stock counts note covers the general rule.
Bundles and merges
ShipBob tracks stock per inventory item, not per bundle SKU. A gift pack of 3 items has no stock of its own; its availability is the lowest of its components divided by the quantity each one takes. A merge goes the other way: several products from several channels resolve to one inventory item, and the inventory_id can change after a merge. The integration reconciles its stored inventory IDs on a schedule, as ShipBob's inventory guide recommends. See kits and bundles.
Reference IDs and shipping methods
An order's reference_id must be unique in the account; a second POST gets 422 Duplicate reference ID. Line items identified by reference_id create a new product when no product with that SKU exists, so a SKU with a trailing space or a changed prefix creates an empty product and the shipment goes to exception for missing stock. The integration checks every SKU against the product list before it posts. The shipping_method text must match the ship option mapping in the ShipBob portal exactly; an unknown value creates a new mapping that defaults to Standard, and an express order ships at standard speed.
Platforms and systems we integrate with ShipBob
ShipBob sits between the store and the customer, and often next to an ERP or inventory system:
- Shopify, WooCommerce, Magento and BigCommerce for orders and stock.
- Cin7, Brightpearl and NetSuite for purchase orders as WROs, stock per location and returns into the books.
- ShipStation when part of the orders ships from your own warehouse.
All flows are listed on integrations. We build the integration for a fixed price, then host, run and monitor it for a monthly fee, with a dashboard, logs and a per-run diff. Before go-live it runs as a dry run that sends nothing to ShipBob. Tell us which store and ERP run next to your ShipBob account.
Frequently asked questions
Should the integration use a Personal Access Token or OAuth?
ShipBob offers both. A Personal Access Token does not expire and has full account access, which suits one merchant's own integration but has to be stored as a secret and rotated by hand. OAuth 2.0 gives an access token valid for 1 hour and a refresh token valid for 30 days, with scopes per resource. Both must be created with the root user of the ShipBob account.
What happens when the same order is sent twice?
ShipBob answers 422 Duplicate reference ID, because reference_id must be unique in the account. The integration treats that answer on a retry as proof the order exists and reads it back with GET orders filtered on ReferenceIds. No second shipment is created. See duplicate customers and orders.
Which stock number goes to the store?
total_fulfillable_quantity: on hand minus committed. ShipBob's total_sellable_quantity adds stock that is still awaiting receipt, so it is higher than what can ship. Bundles are tracked per component, so a bundle's stock is calculated from its parts. A safety buffer per SKU is applied in the integration, as ShipBob's own inventory guide suggests.
Our integration still calls API version 1.0. What now?
Versions 1.0 and 2.0 reached end of support on 31 July 2026. From 8 August 2026 ShipBob blocked a growing share of 1.0 requests, and from 29 August 2026 every 1.0 request returns 410 Gone. The integration has to move to a dated version such as 2026-07, which is supported until 31 July 2028.
How does tracking get back to the store?
Through the order.shipped webhook, which fires when all labels of an order are printed, and order.shipment.tracking.updated for later carrier status. The integration writes carrier and tracking number to the store order and marks the fulfillment there. A poll on LastTrackingUpdateStartDate catches anything a webhook missed.
Tell us what you need
Tell us which systems you use and what needs to work better. We reply personally within one working day. We help you define the work, then agree the price and timing before you commit.
- You know the price and the timeline before you commit to anything
- We work out the connection that takes the work off your hands
- We handle the build, hosting, monitoring and maintenance
- Your team has less information to retype and fewer discrepancies to chase