shipbob-node-sdk 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -175
- package/dist/WebScraper.js +7 -5
- package/dist/WebScraper.js.map +1 -1
- package/dist/client/2025-07/client/client.gen.d.ts +2 -0
- package/dist/client/2025-07/client/client.gen.js +240 -0
- package/dist/client/2025-07/client/client.gen.js.map +1 -0
- package/dist/client/2025-07/client/index.d.ts +8 -0
- package/dist/client/2025-07/client/index.js +18 -0
- package/dist/client/2025-07/client/index.js.map +1 -0
- package/dist/client/2025-07/client/types.gen.d.ts +117 -0
- package/dist/client/2025-07/client/types.gen.js +4 -0
- package/dist/client/2025-07/client/types.gen.js.map +1 -0
- package/dist/client/2025-07/client/utils.gen.d.ts +33 -0
- package/dist/client/2025-07/client/utils.gen.js +242 -0
- package/dist/client/2025-07/client/utils.gen.js.map +1 -0
- package/dist/client/2025-07/client.gen.d.ts +12 -0
- package/dist/client/2025-07/client.gen.js +7 -0
- package/dist/client/2025-07/client.gen.js.map +1 -0
- package/dist/client/2025-07/core/auth.gen.d.ts +18 -0
- package/dist/client/2025-07/core/auth.gen.js +19 -0
- package/dist/client/2025-07/core/auth.gen.js.map +1 -0
- package/dist/client/2025-07/core/bodySerializer.gen.d.ts +25 -0
- package/dist/client/2025-07/core/bodySerializer.gen.js +61 -0
- package/dist/client/2025-07/core/bodySerializer.gen.js.map +1 -0
- package/dist/client/2025-07/core/params.gen.d.ts +43 -0
- package/dist/client/2025-07/core/params.gen.js +105 -0
- package/dist/client/2025-07/core/params.gen.js.map +1 -0
- package/dist/client/2025-07/core/pathSerializer.gen.d.ts +33 -0
- package/dist/client/2025-07/core/pathSerializer.gen.js +116 -0
- package/dist/client/2025-07/core/pathSerializer.gen.js.map +1 -0
- package/dist/client/2025-07/core/queryKeySerializer.gen.d.ts +18 -0
- package/dist/client/2025-07/core/queryKeySerializer.gen.js +99 -0
- package/dist/client/2025-07/core/queryKeySerializer.gen.js.map +1 -0
- package/dist/client/2025-07/core/serverSentEvents.gen.d.ts +71 -0
- package/dist/client/2025-07/core/serverSentEvents.gen.js +138 -0
- package/dist/client/2025-07/core/serverSentEvents.gen.js.map +1 -0
- package/dist/client/2025-07/core/types.gen.d.ts +78 -0
- package/dist/client/2025-07/core/types.gen.js +4 -0
- package/dist/client/2025-07/core/types.gen.js.map +1 -0
- package/dist/client/2025-07/core/utils.gen.d.ts +19 -0
- package/dist/client/2025-07/core/utils.gen.js +94 -0
- package/dist/client/2025-07/core/utils.gen.js.map +1 -0
- package/dist/client/2025-07/index.d.ts +2 -0
- package/dist/client/2025-07/index.js +73 -0
- package/dist/client/2025-07/index.js.map +1 -0
- package/dist/client/2025-07/sdk.gen.d.ts +380 -0
- package/dist/client/2025-07/sdk.gen.js +778 -0
- package/dist/client/2025-07/sdk.gen.js.map +1 -0
- package/dist/client/2025-07/types.gen.d.ts +7191 -0
- package/dist/client/2025-07/types.gen.js +4 -0
- package/dist/client/2025-07/types.gen.js.map +1 -0
- package/dist/client/2026-01/client/client.gen.d.ts +2 -0
- package/dist/client/2026-01/client/client.gen.js +240 -0
- package/dist/client/2026-01/client/client.gen.js.map +1 -0
- package/dist/client/2026-01/client/index.d.ts +8 -0
- package/dist/client/2026-01/client/index.js +18 -0
- package/dist/client/2026-01/client/index.js.map +1 -0
- package/dist/client/2026-01/client/types.gen.d.ts +117 -0
- package/dist/client/2026-01/client/types.gen.js +4 -0
- package/dist/client/2026-01/client/types.gen.js.map +1 -0
- package/dist/client/2026-01/client/utils.gen.d.ts +33 -0
- package/dist/client/2026-01/client/utils.gen.js +242 -0
- package/dist/client/2026-01/client/utils.gen.js.map +1 -0
- package/dist/client/2026-01/client.gen.d.ts +12 -0
- package/dist/client/2026-01/client.gen.js +7 -0
- package/dist/client/2026-01/client.gen.js.map +1 -0
- package/dist/client/2026-01/core/auth.gen.d.ts +18 -0
- package/dist/client/2026-01/core/auth.gen.js +19 -0
- package/dist/client/2026-01/core/auth.gen.js.map +1 -0
- package/dist/client/2026-01/core/bodySerializer.gen.d.ts +25 -0
- package/dist/client/2026-01/core/bodySerializer.gen.js +61 -0
- package/dist/client/2026-01/core/bodySerializer.gen.js.map +1 -0
- package/dist/client/2026-01/core/params.gen.d.ts +43 -0
- package/dist/client/2026-01/core/params.gen.js +105 -0
- package/dist/client/2026-01/core/params.gen.js.map +1 -0
- package/dist/client/2026-01/core/pathSerializer.gen.d.ts +33 -0
- package/dist/client/2026-01/core/pathSerializer.gen.js +116 -0
- package/dist/client/2026-01/core/pathSerializer.gen.js.map +1 -0
- package/dist/client/2026-01/core/queryKeySerializer.gen.d.ts +18 -0
- package/dist/client/2026-01/core/queryKeySerializer.gen.js +99 -0
- package/dist/client/2026-01/core/queryKeySerializer.gen.js.map +1 -0
- package/dist/client/2026-01/core/serverSentEvents.gen.d.ts +71 -0
- package/dist/client/2026-01/core/serverSentEvents.gen.js +138 -0
- package/dist/client/2026-01/core/serverSentEvents.gen.js.map +1 -0
- package/dist/client/2026-01/core/types.gen.d.ts +78 -0
- package/dist/client/2026-01/core/types.gen.js +4 -0
- package/dist/client/2026-01/core/types.gen.js.map +1 -0
- package/dist/client/2026-01/core/utils.gen.d.ts +19 -0
- package/dist/client/2026-01/core/utils.gen.js +94 -0
- package/dist/client/2026-01/core/utils.gen.js.map +1 -0
- package/dist/client/2026-01/index.d.ts +2 -0
- package/dist/client/2026-01/index.js +73 -0
- package/dist/client/2026-01/index.js.map +1 -0
- package/dist/client/2026-01/sdk.gen.d.ts +450 -0
- package/dist/client/2026-01/sdk.gen.js +848 -0
- package/dist/client/2026-01/sdk.gen.js.map +1 -0
- package/dist/client/2026-01/types.gen.d.ts +7282 -0
- package/dist/client/2026-01/types.gen.js +4 -0
- package/dist/client/2026-01/types.gen.js.map +1 -0
- package/dist/index.d.ts +20 -178
- package/dist/index.js +116 -386
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +61 -1435
- package/dist/types.js +1 -38
- package/dist/types.js.map +1 -1
- package/openapi-1.0.json +8422 -0
- package/openapi-2025-07.json +1 -0
- package/openapi-2026-01.json +1 -0
- package/package.json +6 -9
package/README.md
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
# ShipBob Node SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The ShipBob API is in a state of flux as their 1.0 and 2.0 API versions are set to be deprecated and according to their website their end of support is July 31, 2026 (as of April).
|
|
4
|
+
> After the end-of-support date, legacy versions will no longer be accessible.
|
|
4
5
|
|
|
5
6
|
First of all there are no official SDKs for ShipBob. I'm just dropping this here, in case it will speed up somebody else getting started using their API.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
This SDK exposes some endpoints not available in the OpenAPI including:
|
|
10
|
-
|
|
8
|
+
Originally I wrote a library that had endpoints not available in OpenAPI including:
|
|
11
9
|
- `/2.0/receiving-extended`
|
|
12
10
|
- `/2.0/product`
|
|
13
11
|
- `/experimental/product` :skull:
|
|
14
12
|
- `/experimental/receiving` :skull:
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
It was so cumbersome to keep up-to-date and their API versions are set to expire after 1 year, so it only makes sense to use their OpenAPI spec to generate a client.
|
|
15
|
+
|
|
16
|
+
The nice thing about this lib is that it uses tree-shaking, but it's not as friendly to use as the original version. You will need to have a "POST" send the `body` and a "GET" will use `query`. `path` will be needed when a parameter is part of the url. So, you'll need to refer to the API to be able to use this.
|
|
18
17
|
|
|
19
18
|
<div align="center">
|
|
20
19
|
<a href="https://www.npmjs.com/package/shipbob-node-sdk">
|
|
@@ -32,6 +31,13 @@ npm i shipbob-node-sdk
|
|
|
32
31
|
yarn add shipbob-node-sdk
|
|
33
32
|
```
|
|
34
33
|
|
|
34
|
+
```typescript
|
|
35
|
+
// create your client like this (return object has extra functions/objects)
|
|
36
|
+
const client = await createAPI('<your-token-here>', 'https://sandbox-api.shipbob.com');
|
|
37
|
+
// client is passed automatically
|
|
38
|
+
const productSearch = await get202601Product();
|
|
39
|
+
```
|
|
40
|
+
|
|
35
41
|
Have a look in the `/test` folder. You might like more something like PostMan, but you can run and debug these "tests" in VS Code. You need a `.env` file like this:
|
|
36
42
|
|
|
37
43
|
```bash
|
|
@@ -45,140 +51,18 @@ SHIPBOB_WEB_UI_EMAIL=email@company.com
|
|
|
45
51
|
SHIPBOB_WEB_UI_PASSWORD=<redacted>
|
|
46
52
|
```
|
|
47
53
|
|
|
48
|
-
# API implementation
|
|
49
|
-
|
|
50
|
-
## Legend
|
|
51
|
-
|
|
52
|
-
:x: = I haven't needed this
|
|
53
|
-
|
|
54
|
-
:heavy_check_mark: = implemented
|
|
55
|
-
|
|
56
|
-
- [ ] = intend to add
|
|
57
|
-
|
|
58
|
-
:question: = might add support soon - under investigation
|
|
59
|
-
|
|
60
|
-
## Orders
|
|
61
|
-
|
|
62
|
-
- :x: Estimate Fulfillment Cost For Order
|
|
63
|
-
- :question: Get Order - don't see the point of this endpoint, unless you store their Ids
|
|
64
|
-
- :heavy_check_mark: Get Orders: api.getOrders(...)
|
|
65
|
-
- :heavy_check_mark: Create Order: api.placeOrder(...)
|
|
66
|
-
- :heavy_check_mark: Cancel single Order by Order ID: api.cancelSingleOrderByOrderId()
|
|
67
|
-
- :x: Get Order Store Json
|
|
68
|
-
- :x: Save the Store Order Json (The JSON that represent the order on the Third Party Source)
|
|
69
|
-
- :heavy_check_mark: Get one Shipment by Order Id and Shipment Id: `api.getOneShipmentByOrderIdAndShipmentId(...)`
|
|
70
|
-
- :x: Cancel one Shipment by Order Id and Shipment Id
|
|
71
|
-
- :x: Get one Shipment's status timeline by Order Id and Shipment Id
|
|
72
|
-
- :question: Get all Shipments for Order
|
|
73
|
-
- :x: Get logs for one Shipment by Order Id and Shipment Id
|
|
74
|
-
- :x: Get one Shipment by Shipment Id
|
|
75
|
-
- :x: Update a Shipment
|
|
76
|
-
- :x: Cancel one Shipment by Shipment Id
|
|
77
|
-
- :x: Cancel multiple Shipments by Shipment Id
|
|
78
|
-
- :x: Get one Shipment's status timeline by Shipment Id
|
|
79
|
-
- :x: Get logs for one Shipment by Shipment Id
|
|
80
|
-
- :heavy_check_mark: Get shipping methods: api.getShippingMethods()
|
|
81
|
-
|
|
82
|
-
## Shipments
|
|
83
|
-
|
|
84
|
-
Turns out the webhooks aren't reliable, so polling is needed to get shipment information.
|
|
85
|
-
|
|
86
|
-
1. `order_shipped` webhook can fire without tracking details
|
|
87
|
-
2. `shipment_delivered` webhook may not be sent. Additionally, exceptions (return to sender) have no webhook.
|
|
88
|
-
|
|
89
|
-
- :heavy_check_mark: Get one Shipment by Shipment Id: `api.getOneShipment()`
|
|
90
|
-
- :x: Update a Shipment (marked with tracking information uploaded to a third-party system where the order originated)
|
|
91
|
-
- :question: Cancel one Shipment by Shipment Id
|
|
92
|
-
- :x: Cancel multiple Shipments by Shipment Id
|
|
93
|
-
- :x: Get one Shipment's status timeline by Shipment Id
|
|
94
|
-
- :x: Get logs for one Shipment by Shipment Id
|
|
95
|
-
- :heavy_check_mark: Get shipping methods: `api.getShippingMethods()`
|
|
96
|
-
|
|
97
|
-
## Products 1.0
|
|
98
|
-
|
|
99
|
-
- :heavy_check_mark: Get multiple products: `api.getProducts1_0(...)`
|
|
100
|
-
- :heavy_check_mark: Add a single product to the store: `api.createProduct1_0(...)`
|
|
101
|
-
- :x: Modify a single product (using 2.0 for additional properties)
|
|
102
|
-
- :x: Add multiple products to the store
|
|
103
|
-
|
|
104
|
-
## Products 2.0
|
|
105
|
-
|
|
106
|
-
These are not documented on the site yet:
|
|
107
|
-
|
|
108
|
-
- :heavy_check_mark: Get multiple products: `api.getProducts2_0(...)`
|
|
109
|
-
- :heavy_check_mark: Add a single product to the store: `api.createProduct2_0(...)`
|
|
110
|
-
- :heavy_check_mark: Modify a single product: `api.updateProducts2_0(...)`
|
|
111
|
-
- :x: Add multiple products to the store
|
|
112
|
-
|
|
113
|
-
## Products Experimental
|
|
114
|
-
|
|
115
|
-
Kindly note as it's experimental subject to change/removal :skull:
|
|
116
|
-
|
|
117
|
-
- :heavy_check_mark: Get multiple products: `api.getProductsExperimental(...)`
|
|
118
|
-
- :heavy_check_mark: Add a single product to the store: `api.createProductExperimental(...)`
|
|
119
|
-
- :heavy_check_mark: Modify a single product: `api.updateProductsExperimental(...)`
|
|
120
|
-
- :x: Add multiple products to the store
|
|
121
|
-
|
|
122
|
-
## Inventory
|
|
123
|
-
|
|
124
|
-
- [ ] Get an inventory item
|
|
125
|
-
- :heavy_check_mark: List inventory items: `api.listInventory(...)`
|
|
126
|
-
- :x: Get a list of inventory items by product id (we don't know product_id)
|
|
127
|
-
|
|
128
|
-
## Channels
|
|
129
|
-
|
|
130
|
-
- :heavy_check_mark: Get user-authorized channels `api.getChannels()`
|
|
131
|
-
|
|
132
|
-
**NOTE:** This fails with a web UI scraper account (you need `channels_read` scope)
|
|
133
|
-
|
|
134
|
-
## Returns
|
|
135
|
-
|
|
136
|
-
- :question: Get Return Order
|
|
137
|
-
- :question: Modify Return Order
|
|
138
|
-
- :question: Get Return Orders
|
|
139
|
-
- :question: Create Return Order
|
|
140
|
-
- :question: Cancel Return Order
|
|
141
|
-
- :question: Get One Return's status history
|
|
54
|
+
# API implementation
|
|
55
|
+
Everything is implemented except for the `/simulate/*` endpoints, which are not in OpenAPI. You can look at the `/test/shipbob-api.simulate.spec.ts` to see how to call them.
|
|
142
56
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
- :heavy_check_mark: Get Fulfillment Centers: `api.getFulfillmentCenters()`
|
|
146
|
-
- :heavy_check_mark: Get Warehouse Receiving Order: `api.getWarehouseReceivingOrder(...)`
|
|
147
|
-
- :heavy_check_mark: Get Warehouse Receiving Order Boxes: `api.getWarehouseReceivingOrderBoxes(...)`
|
|
148
|
-
- :x: Get Multiple Warehouse Receiving Orders (using receiving-extended instead)
|
|
149
|
-
- :heavy_check_mark: Create Warehouse Receiving Order: `api.createWarehouseReceivingOrder(...)`
|
|
150
|
-
- :x: Get Warehouse Receiving Order Box Labels
|
|
151
|
-
- :x: Cancel Warehouse Receiving Order (could be done manually, if needed?)
|
|
152
|
-
- :x: 5 x DEPRECATED '/1.0/receiving
|
|
153
|
-
- Get Warehouse Receiving Order
|
|
154
|
-
- Get a Warehouse Receiving Order by Purchase Order Number
|
|
155
|
-
- Create Warehouse Receiving Order
|
|
156
|
-
- Get Warehouse Receiving Order Box Labels
|
|
157
|
-
- Cancel Warehouse Receiving Order
|
|
158
|
-
|
|
159
|
-
## Receiving-Extended (not in API docs)
|
|
160
|
-
|
|
161
|
-
- :heavy_check_mark: Get Receiving Extended: `api.getReceivingExtended(...)` (will include this in a recipe that uses SetExternalSync)
|
|
162
|
-
|
|
163
|
-
## Receiving Experimental
|
|
164
|
-
|
|
165
|
-
Kindly note as it's experimental subject to change/removal :skull:
|
|
166
|
-
|
|
167
|
-
- :heavy_check_mark: Receiving Set External Sync: `api.experimentalReceivingSetExternalSync(...)`
|
|
168
|
-
|
|
169
|
-
**NOTE:** See the section below `How to sync WROs` for some guidance.
|
|
57
|
+
I'll probably look at a way to have the client creation pick up the library version using a factory. To start it's only `2026-01` version.
|
|
170
58
|
|
|
171
59
|
## Webhooks
|
|
172
60
|
|
|
173
|
-
- :heavy_check_mark: Get Webhooks: `api.getWebhooks()`
|
|
174
|
-
- :heavy_check_mark: Create a new webhook subscription: `api.registerWebhookSubscription(...)`
|
|
175
|
-
- :heavy_check_mark: Delete an existing webhook subscription: `api.unregisterWebhookSubscription(...)`
|
|
176
|
-
|
|
177
61
|
As a personal note. I regret implementing webhooks at all, since I needed to implement polling anyway. There are various gaps in the webhooks. Using their table is perhaps the best way to explain:
|
|
178
62
|
|
|
179
63
|
| Shipment Status | Status Detail Name | Comment |
|
|
180
64
|
| --------------- | ------------------ | ----------------------------------------------------------------------------------------------- |
|
|
181
|
-
| Processing | Labeled | I think this maps to "
|
|
65
|
+
| Processing | Labeled | I think this maps to "order.shipped" webhook, doesn't always have tracking (or invoice amounts) |
|
|
182
66
|
| Completed | Delivered | Does not always fire when delivered (seems to be carrier dependent) |
|
|
183
67
|
| Completed | Delivery Exception | No Webhook (need to poll for RTS, etc.) |
|
|
184
68
|
| Exception | \* | These do fire, but are not useful for delivery |
|
|
@@ -187,35 +71,42 @@ ie: No webhooks for delivery exceptions ie: `Completed` -> `DeliveryException` w
|
|
|
187
71
|
|
|
188
72
|
Partial rows of table from here: _(https://developer.shipbob.com/#shipment-statuses)_
|
|
189
73
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
- :x: Get locations
|
|
74
|
+
The typings of webhooks - i'll try to update those. It's basically an order and the status is known. For some bizarre reason receiving has no webhooks.
|
|
193
75
|
|
|
194
76
|
## Follow URIs
|
|
195
77
|
|
|
196
78
|
This is not part of the API, but instead allows you to follow URI's returned in the API (see tests for examples). They use some kind of HATEOAS, but it's inconsistent across API versions.
|
|
197
79
|
|
|
198
|
-
|
|
80
|
+
:heavy_check_mark: Ols API versions retrieve a path from a provided resource ie: header `next-page`: `api.getPath<T>(response.headers['next-page'])`
|
|
81
|
+
|
|
82
|
+
latest version is part of JSON response:
|
|
83
|
+
```typescript
|
|
84
|
+
import { createAPI } from 'shipbob-node-sdk';
|
|
85
|
+
import { get202601Product } from 'shipbob-node-sdk/dist/client/2026-01';
|
|
86
|
+
import { type Get202601ProductResponses, type Get202601ProductErrors} from 'shipbob-node-sdk/dist/client/2026-01/types.gen';
|
|
199
87
|
|
|
88
|
+
const client = await createAPI('<your-token-here>', 'https://sandbox-api.shipbob.com', undefined, {
|
|
89
|
+
logTraffic: true,
|
|
90
|
+
});
|
|
91
|
+
const productSearch = await get202601Product();
|
|
92
|
+
assert.ok(productSearch.data, 'should have data');
|
|
93
|
+
const { next } = productSearch.data;
|
|
94
|
+
assert.ok(next !== null && next !== undefined, 'should have more pages');
|
|
95
|
+
// you can get these types by clicking ie: `get202601Product` function and look at typings parameters.
|
|
96
|
+
const pagedResult = await client.get<Get202601ProductResponses, Get202601ProductErrors>(next);
|
|
97
|
+
assert.ok(pagedResult.data, 'should have paged data');
|
|
98
|
+
```
|
|
200
99
|
# Building locally
|
|
201
100
|
|
|
202
101
|
For making changes to this library locally - use `yarn link` to test out the changes easily. This is useful if you would like to contribute.
|
|
102
|
+
If you don't want an NPM dependency, it's easy to generate this yourself from OpenAPI spec and then just copy the index.ts file to your project.
|
|
203
103
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
Not really sure anybody will ever need this as many common platforms probably have integrations. There are a couple of other community SDKs. They do not have `/2.0/*` or `/experimental/*` endpoints:
|
|
207
|
-
|
|
208
|
-
- [shipbob-sdk-python](https://github.com/community-phone-company/shipbob-sdk-python)
|
|
209
|
-
- [shipbob-go](https://github.com/stryd/shipbob-go) - generated from Open API
|
|
210
|
-
|
|
211
|
-
NOTE: I did not notice until all this code was written that ShipBob had published an Open API spec :facepunch:. You may have better luck generating your own client. Maybe those generated typings at least belong here.
|
|
104
|
+
NOTE: I did not notice until I had written a custom implementation that ShipBob had published an Open API spec :facepunch:.
|
|
212
105
|
|
|
213
106
|
```bash
|
|
214
|
-
|
|
107
|
+
# this is how the clients are generated (see scripts in package.json)
|
|
108
|
+
$ yarn generate:2026-01
|
|
215
109
|
```
|
|
216
|
-
|
|
217
|
-
The included script using OpenAPI can generate clients in various languages.
|
|
218
|
-
|
|
219
110
|
# Testing
|
|
220
111
|
|
|
221
112
|
You can fake out this library itself, or otherwise mocking the ShipBob API http calls are quite easy to simulate with `nock`. Here's a way to test creating an order verifying idempotent operation.
|
|
@@ -288,7 +179,7 @@ for (const event of events) {
|
|
|
288
179
|
|
|
289
180
|
You can publish that as an event or push to a queue and it will act as a "webhook".
|
|
290
181
|
|
|
291
|
-
**NOTE:** I discovered after writing the above inbound mail handler that a WRO you create may be split. ie: we created 1 WRO and it was split into 6 more WROs by the ShipBob team, so it's not really possible to link back to your system when that occurs.
|
|
182
|
+
**NOTE:** I discovered after writing the above inbound mail handler that a WRO you create may be split. ie: we created 1 WRO and it was split into 6 more WROs by the ShipBob team, so it's not really possible to link back to your system when that occurs. Also, they have indicated to me there's no link on these WROs or UROs (Unidentified Receiving Orders) that they create. There's no hierarchical relationship with the split WROs they are creating. In other words, you will need to implement polling anyway, so adding this is probably not worthwhile.
|
|
292
183
|
|
|
293
184
|
# OAuth
|
|
294
185
|
|
|
@@ -311,6 +202,8 @@ There is no documentation for these extra APIs - you can look through network tr
|
|
|
311
202
|
|
|
312
203
|
```typescript
|
|
313
204
|
// scrape web.shipbob.com website:
|
|
205
|
+
import { getAccessTokenUI } from 'shipbob-node-sdk';
|
|
206
|
+
|
|
314
207
|
const authResponse = await getAccessTokenUI({
|
|
315
208
|
email,
|
|
316
209
|
password,
|
|
@@ -329,13 +222,16 @@ const inventoryListResponse = await webUIAPI.listInventory({ Ids: [20104984] });
|
|
|
329
222
|
|
|
330
223
|
This is a suggested way to track orders from ShipBob. This may be better than using the webhook, sometimes the `order_shipped` webhook fires with no tracking information.
|
|
331
224
|
|
|
332
|
-
1. Poll GET `/
|
|
225
|
+
1. Poll GET `/2026-01/order?HasTracking=true&IsTrackingUploaded=false&startDate=03-25-2025`
|
|
333
226
|
|
|
334
227
|
```typescript
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
228
|
+
// right now for me I get error "An unexpected database error occurred. Please try again later", but it worked on 1.0 API
|
|
229
|
+
const result = await get202601Order({
|
|
230
|
+
query: {
|
|
231
|
+
HasTracking: true,
|
|
232
|
+
IsTrackingUploaded: false,
|
|
233
|
+
StartDate: '2025-03-25T14:15:22Z',
|
|
234
|
+
},
|
|
339
235
|
});
|
|
340
236
|
```
|
|
341
237
|
|
|
@@ -343,8 +239,6 @@ const results = await api.getOrders({
|
|
|
343
239
|
3. Sync the tracking back to your platform
|
|
344
240
|
4. Mark the order as shipped using this endpoint (https://developer.shipbob.com/api-docs/#tag/Orders/paths/~11.0~1shipment~1%7BshipmentId%7D/put). Or, you can mark it as shipped using the bulk mark as shipped endpoint (https://developer.shipbob.com/api-docs/#tag/Orders/paths/~11.0~1shipment~1:bulkUpdateTrackingUpload/post).
|
|
345
241
|
|
|
346
|
-
**NOTE:** `PUT`/`POST` to `/1.0/shipment` not implemented in this library yet.
|
|
347
|
-
|
|
348
242
|
# How to sync WROs
|
|
349
243
|
|
|
350
244
|
Syncing WROs (Warehouse Receiving Orders) back to your system has 2 options.
|
|
@@ -352,13 +246,17 @@ Syncing WROs (Warehouse Receiving Orders) back to your system has 2 options.
|
|
|
352
246
|
## Option #1 - Simple (wait until the WRO status is Completed)
|
|
353
247
|
|
|
354
248
|
- Poll our GET WRO endpoint for WROs in Completed status:
|
|
355
|
-
GET https://sandbox-api.shipbob.com/
|
|
249
|
+
GET https://sandbox-api.shipbob.com/2026-01/receiving?Statuses=Completed&ExternalSync=false
|
|
356
250
|
|
|
357
251
|
```typescript
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
252
|
+
/**
|
|
253
|
+
* this was /2.0/receiving-extended
|
|
254
|
+
*/
|
|
255
|
+
const response = await get202601Receiving({
|
|
256
|
+
query: {
|
|
257
|
+
Statuses: 'Completed',
|
|
258
|
+
ExternalSync: false,
|
|
259
|
+
},
|
|
362
260
|
});
|
|
363
261
|
```
|
|
364
262
|
|
|
@@ -368,28 +266,31 @@ const results = await api.getReceivingExtended({
|
|
|
368
266
|
|
|
369
267
|
Mark the WRO as synced (this is optional and a alternative option to continuously polling completed WROs that you may or may not know you have already synced)
|
|
370
268
|
|
|
371
|
-
POST https://sandbox-api.shipbob.com/experimental/receiving/:set-external-sync
|
|
372
|
-
|
|
373
|
-
```json
|
|
374
|
-
{
|
|
375
|
-
"ids": [442946],
|
|
376
|
-
"is_external_sync": true
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
269
|
```typescript
|
|
381
|
-
// with this library
|
|
382
270
|
// use Ids from "getReceivingExtended" with ExternalSync: false.
|
|
383
|
-
const
|
|
271
|
+
const response = await post202601ReceivingSetExternalSync({
|
|
272
|
+
body: {
|
|
273
|
+
ids: [918363],
|
|
274
|
+
is_external_sync: true,
|
|
275
|
+
},
|
|
276
|
+
});
|
|
384
277
|
```
|
|
385
278
|
|
|
386
279
|
## Option #2 - Advanced (partial receiving)
|
|
387
280
|
|
|
388
|
-
- Poll
|
|
281
|
+
- Poll GET WRO endpoint for WROs with statuses "processing" and "completed": https://sandbox-api.shipbob.com/2026-01/receiving?Statuses=Processing,Completed&ExternalSync=false.
|
|
282
|
+
```typescript
|
|
283
|
+
const response = await get202601Receiving({
|
|
284
|
+
query: {
|
|
285
|
+
Statuses: 'Processing',
|
|
286
|
+
ExternalSync: false,
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
```
|
|
389
290
|
|
|
390
291
|
**Note:** When initially testing you can remove the statuses from the query params, and you will see the default status of "AwaitingArrival" whenever a WRO is created. There is no sandbox simulation to move these forward.
|
|
391
292
|
|
|
392
|
-
- For each WRO, make a request to the Get Warehouse Receiving Order Boxes endpoint: https://sandbox-api.shipbob.com/
|
|
293
|
+
- For each WRO, make a request to the Get Warehouse Receiving Order Boxes endpoint: https://sandbox-api.shipbob.com/2026-01/receiving/442997/boxes
|
|
393
294
|
- Iterate through each box
|
|
394
295
|
- Iterate through each item in the box_items array
|
|
395
296
|
- Sync the stowed_quantity for each item back to your system
|
|
@@ -402,6 +303,8 @@ So, if you have one FC, you can use total_sellable_quantity for each inventory i
|
|
|
402
303
|
|
|
403
304
|
For multiple FCs - their recommendation is to use for each FC the fulfillable_quantity and subtract the total_exception_quantity (since it could be assigned to either FC).
|
|
404
305
|
|
|
306
|
+
You can't do this anymore in `2026-01` - it will require 2 separate API calls inventory-levels and inventory-levels-location. I'll try to update this - just trying to publish 202601.
|
|
307
|
+
|
|
405
308
|
```json
|
|
406
309
|
{
|
|
407
310
|
"id": 1234,
|
package/dist/WebScraper.js
CHANGED
|
@@ -10,15 +10,17 @@ const SAVE_TOKEN_PAGE = '/Account/SaveToken';
|
|
|
10
10
|
* Attempt to login and return an auth token (that can in turn be used to access API)
|
|
11
11
|
*/
|
|
12
12
|
const loginShipBob = async (page, credentials, waitTimoutInSeconds = 30) => {
|
|
13
|
-
//
|
|
14
|
-
await page.goto('https://web.shipbob.com
|
|
13
|
+
// this page has both email/username + password!
|
|
14
|
+
await page.goto('https://web.shipbob.com', {
|
|
15
15
|
timeout: 0, // no timeout - it's a slow page
|
|
16
16
|
});
|
|
17
|
-
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
17
|
+
// await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
18
18
|
await page.waitForSelector('input[name=Username]');
|
|
19
19
|
// <input name="Username" type="email" data-sb-automation="username-input" ...>
|
|
20
20
|
await page.type('input[name=Username]', credentials.email);
|
|
21
|
-
|
|
21
|
+
await page.click('#login-button');
|
|
22
|
+
console.log(' > Login clicked first time (checking SSO - waiting for password input)');
|
|
23
|
+
await page.waitForSelector('input[name=Password]');
|
|
22
24
|
// <input name="Password" id="password-input" type="password" data-sb-automation="password-input">
|
|
23
25
|
await page.type('input[name=Password]', credentials.password);
|
|
24
26
|
// we will attach to this context as we progress authentication
|
|
@@ -99,7 +101,7 @@ const loginShipBob = async (page, credentials, waitTimoutInSeconds = 30) => {
|
|
|
99
101
|
});
|
|
100
102
|
// kick off login process - navigation listeners are already registered
|
|
101
103
|
Promise.all([page.waitForNavigation({ waitUntil: 'networkidle0' }), page.click('#login-button')]).then(() => {
|
|
102
|
-
console.log(' > Login clicked (interceptors are running)');
|
|
104
|
+
console.log(' > Login clicked second time (interceptors are running)');
|
|
103
105
|
});
|
|
104
106
|
});
|
|
105
107
|
return interceptorPromise;
|
package/dist/WebScraper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebScraper.js","sourceRoot":"","sources":["../src/WebScraper.ts"],"names":[],"mappings":";;;AAAA,yCAAqD;AAcrD;;GAEG;AACH,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAQ7C;;GAEG;AACH,MAAM,YAAY,GAAG,KAAK,EAAE,IAAU,EAAE,WAAwB,EAAE,mBAAmB,GAAG,EAAE,EAAyB,EAAE;IACnH,
|
|
1
|
+
{"version":3,"file":"WebScraper.js","sourceRoot":"","sources":["../src/WebScraper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// This file is auto-generated by @hey-api/openapi-ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createClient = void 0;
|
|
5
|
+
const serverSentEvents_gen_1 = require("../core/serverSentEvents.gen");
|
|
6
|
+
const utils_gen_1 = require("../core/utils.gen");
|
|
7
|
+
const utils_gen_2 = require("./utils.gen");
|
|
8
|
+
const createClient = (config = {}) => {
|
|
9
|
+
let _config = (0, utils_gen_2.mergeConfigs)((0, utils_gen_2.createConfig)(), config);
|
|
10
|
+
const getConfig = () => ({ ..._config });
|
|
11
|
+
const setConfig = (config) => {
|
|
12
|
+
_config = (0, utils_gen_2.mergeConfigs)(_config, config);
|
|
13
|
+
return getConfig();
|
|
14
|
+
};
|
|
15
|
+
const interceptors = (0, utils_gen_2.createInterceptors)();
|
|
16
|
+
const beforeRequest = async (options) => {
|
|
17
|
+
const opts = {
|
|
18
|
+
..._config,
|
|
19
|
+
...options,
|
|
20
|
+
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
21
|
+
headers: (0, utils_gen_2.mergeHeaders)(_config.headers, options.headers),
|
|
22
|
+
serializedBody: undefined,
|
|
23
|
+
};
|
|
24
|
+
if (opts.security) {
|
|
25
|
+
await (0, utils_gen_2.setAuthParams)({
|
|
26
|
+
...opts,
|
|
27
|
+
security: opts.security,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (opts.requestValidator) {
|
|
31
|
+
await opts.requestValidator(opts);
|
|
32
|
+
}
|
|
33
|
+
if (opts.body !== undefined && opts.bodySerializer) {
|
|
34
|
+
opts.serializedBody = opts.bodySerializer(opts.body);
|
|
35
|
+
}
|
|
36
|
+
// remove Content-Type header if body is empty to avoid sending invalid requests
|
|
37
|
+
if (opts.body === undefined || opts.serializedBody === '') {
|
|
38
|
+
opts.headers.delete('Content-Type');
|
|
39
|
+
}
|
|
40
|
+
const resolvedOpts = opts;
|
|
41
|
+
const url = (0, utils_gen_2.buildUrl)(resolvedOpts);
|
|
42
|
+
return { opts: resolvedOpts, url };
|
|
43
|
+
};
|
|
44
|
+
const request = async (options) => {
|
|
45
|
+
const { opts, url } = await beforeRequest(options);
|
|
46
|
+
const requestInit = {
|
|
47
|
+
redirect: 'follow',
|
|
48
|
+
...opts,
|
|
49
|
+
body: (0, utils_gen_1.getValidRequestBody)(opts),
|
|
50
|
+
};
|
|
51
|
+
let request = new Request(url, requestInit);
|
|
52
|
+
for (const fn of interceptors.request.fns) {
|
|
53
|
+
if (fn) {
|
|
54
|
+
request = await fn(request, opts);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// fetch must be assigned here, otherwise it would throw the error:
|
|
58
|
+
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
59
|
+
const _fetch = opts.fetch;
|
|
60
|
+
let response;
|
|
61
|
+
try {
|
|
62
|
+
response = await _fetch(request);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// Handle fetch exceptions (AbortError, network errors, etc.)
|
|
66
|
+
let finalError = error;
|
|
67
|
+
for (const fn of interceptors.error.fns) {
|
|
68
|
+
if (fn) {
|
|
69
|
+
finalError = (await fn(error, undefined, request, opts));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
finalError = finalError || {};
|
|
73
|
+
if (opts.throwOnError) {
|
|
74
|
+
throw finalError;
|
|
75
|
+
}
|
|
76
|
+
// Return error response
|
|
77
|
+
return opts.responseStyle === 'data'
|
|
78
|
+
? undefined
|
|
79
|
+
: {
|
|
80
|
+
error: finalError,
|
|
81
|
+
request,
|
|
82
|
+
response: undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
for (const fn of interceptors.response.fns) {
|
|
86
|
+
if (fn) {
|
|
87
|
+
response = await fn(response, request, opts);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const result = {
|
|
91
|
+
request,
|
|
92
|
+
response,
|
|
93
|
+
};
|
|
94
|
+
if (response.ok) {
|
|
95
|
+
const parseAs = (opts.parseAs === 'auto'
|
|
96
|
+
? (0, utils_gen_2.getParseAs)(response.headers.get('Content-Type'))
|
|
97
|
+
: opts.parseAs) ?? 'json';
|
|
98
|
+
if (response.status === 204 || response.headers.get('Content-Length') === '0') {
|
|
99
|
+
let emptyData;
|
|
100
|
+
switch (parseAs) {
|
|
101
|
+
case 'arrayBuffer':
|
|
102
|
+
case 'blob':
|
|
103
|
+
case 'text':
|
|
104
|
+
emptyData = await response[parseAs]();
|
|
105
|
+
break;
|
|
106
|
+
case 'formData':
|
|
107
|
+
emptyData = new FormData();
|
|
108
|
+
break;
|
|
109
|
+
case 'stream':
|
|
110
|
+
emptyData = response.body;
|
|
111
|
+
break;
|
|
112
|
+
case 'json':
|
|
113
|
+
default:
|
|
114
|
+
emptyData = {};
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
return opts.responseStyle === 'data'
|
|
118
|
+
? emptyData
|
|
119
|
+
: {
|
|
120
|
+
data: emptyData,
|
|
121
|
+
...result,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
let data;
|
|
125
|
+
switch (parseAs) {
|
|
126
|
+
case 'arrayBuffer':
|
|
127
|
+
case 'blob':
|
|
128
|
+
case 'formData':
|
|
129
|
+
case 'text':
|
|
130
|
+
data = await response[parseAs]();
|
|
131
|
+
break;
|
|
132
|
+
case 'json': {
|
|
133
|
+
// Some servers return 200 with no Content-Length and empty body.
|
|
134
|
+
// response.json() would throw; read as text and parse if non-empty.
|
|
135
|
+
const text = await response.text();
|
|
136
|
+
data = text ? JSON.parse(text) : {};
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'stream':
|
|
140
|
+
return opts.responseStyle === 'data'
|
|
141
|
+
? response.body
|
|
142
|
+
: {
|
|
143
|
+
data: response.body,
|
|
144
|
+
...result,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (parseAs === 'json') {
|
|
148
|
+
if (opts.responseValidator) {
|
|
149
|
+
await opts.responseValidator(data);
|
|
150
|
+
}
|
|
151
|
+
if (opts.responseTransformer) {
|
|
152
|
+
data = await opts.responseTransformer(data);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return opts.responseStyle === 'data'
|
|
156
|
+
? data
|
|
157
|
+
: {
|
|
158
|
+
data,
|
|
159
|
+
...result,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const textError = await response.text();
|
|
163
|
+
let jsonError;
|
|
164
|
+
try {
|
|
165
|
+
jsonError = JSON.parse(textError);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// noop
|
|
169
|
+
}
|
|
170
|
+
const error = jsonError ?? textError;
|
|
171
|
+
let finalError = error;
|
|
172
|
+
for (const fn of interceptors.error.fns) {
|
|
173
|
+
if (fn) {
|
|
174
|
+
finalError = (await fn(error, response, request, opts));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
finalError = finalError || {};
|
|
178
|
+
if (opts.throwOnError) {
|
|
179
|
+
throw finalError;
|
|
180
|
+
}
|
|
181
|
+
// TODO: we probably want to return error and improve types
|
|
182
|
+
return opts.responseStyle === 'data'
|
|
183
|
+
? undefined
|
|
184
|
+
: {
|
|
185
|
+
error: finalError,
|
|
186
|
+
...result,
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const makeMethodFn = (method) => (options) => request({ ...options, method });
|
|
190
|
+
const makeSseFn = (method) => async (options) => {
|
|
191
|
+
const { opts, url } = await beforeRequest(options);
|
|
192
|
+
return (0, serverSentEvents_gen_1.createSseClient)({
|
|
193
|
+
...opts,
|
|
194
|
+
body: opts.body,
|
|
195
|
+
headers: opts.headers,
|
|
196
|
+
method,
|
|
197
|
+
onRequest: async (url, init) => {
|
|
198
|
+
let request = new Request(url, init);
|
|
199
|
+
for (const fn of interceptors.request.fns) {
|
|
200
|
+
if (fn) {
|
|
201
|
+
request = await fn(request, opts);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return request;
|
|
205
|
+
},
|
|
206
|
+
serializedBody: (0, utils_gen_1.getValidRequestBody)(opts),
|
|
207
|
+
url,
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
const _buildUrl = (options) => (0, utils_gen_2.buildUrl)({ ..._config, ...options });
|
|
211
|
+
return {
|
|
212
|
+
buildUrl: _buildUrl,
|
|
213
|
+
connect: makeMethodFn('CONNECT'),
|
|
214
|
+
delete: makeMethodFn('DELETE'),
|
|
215
|
+
get: makeMethodFn('GET'),
|
|
216
|
+
getConfig,
|
|
217
|
+
head: makeMethodFn('HEAD'),
|
|
218
|
+
interceptors,
|
|
219
|
+
options: makeMethodFn('OPTIONS'),
|
|
220
|
+
patch: makeMethodFn('PATCH'),
|
|
221
|
+
post: makeMethodFn('POST'),
|
|
222
|
+
put: makeMethodFn('PUT'),
|
|
223
|
+
request,
|
|
224
|
+
setConfig,
|
|
225
|
+
sse: {
|
|
226
|
+
connect: makeSseFn('CONNECT'),
|
|
227
|
+
delete: makeSseFn('DELETE'),
|
|
228
|
+
get: makeSseFn('GET'),
|
|
229
|
+
head: makeSseFn('HEAD'),
|
|
230
|
+
options: makeSseFn('OPTIONS'),
|
|
231
|
+
patch: makeSseFn('PATCH'),
|
|
232
|
+
post: makeSseFn('POST'),
|
|
233
|
+
put: makeSseFn('PUT'),
|
|
234
|
+
trace: makeSseFn('TRACE'),
|
|
235
|
+
},
|
|
236
|
+
trace: makeMethodFn('TRACE'),
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
exports.createClient = createClient;
|
|
240
|
+
//# sourceMappingURL=client.gen.js.map
|