Hub Gateway API
Create Order
Place a B2B dropship order for a Hub buyer's cloud lines.
POST /api/hub/ordersUse Case
Place a real B2B dropship order for a Hub buyer's cloud lines. The distributor
(reseller) is billed on net terms; the recipient is the end customer. Stock is
reserved in the same transaction, and the delivery fee is re-validated
server-side.
Idempotent on reference (stored as the order group's external reference): a
re-fire returns the existing order numbers instead of duplicating. The publish
gate and per-product authorization are re-asserted at order time.
Header Parameters
| Parameter | Data Type | Required | Description |
|---|---|---|---|
x-hub-api-key | string | true | Shared Hub service key. |
Content-Type | string | true | application/json. |
Request Body Parameters
| Parameter | Data Type | Required | Description |
|---|---|---|---|
hubCustomerId | string | true | Distributor placing the order. |
reference | string | true | Idempotency key (stored as orderGroup.externalRef). |
recipient | object | true | Ship-to address (end customer). |
recipient.name | string | true | Recipient name. |
recipient.street | string | true | Street address. |
recipient.city | string | true | City. |
recipient.state | string | true | State / region. |
recipient.postalCode | string | true | Postal / ZIP code. |
recipient.country | string | true | Country. |
recipient.phone | string | false | Phone. |
items | array | true | Order lines (≥ 1). |
items[].orderKey | string | true | The B2B variant.id. |
items[].qty | integer | true | Positive quantity. |
deliveryFeeCents | integer | false | If supplied, must equal the server quote. |
Example Request
curl -X POST "https://<your-b2b-host>/api/hub/orders" \
-H "x-hub-api-key: $HUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"hubCustomerId": "hub_cust_1",
"reference": "hub-order-9f2a",
"recipient": {
"name": "Jane Buyer", "street": "1 Main St", "city": "Austin",
"state": "TX", "postalCode": "78701", "country": "US", "phone": "+1…"
},
"items": [ { "orderKey": "var_abc", "qty": 2 } ],
"deliveryFeeCents": 1500
}'Response Parameters
| Parameter | Data Type | Description |
|---|---|---|
reference | string | Echoed idempotency key. |
orderNumbers | array | The created B2B sub-order numbers. |
status | string | pending on creation. |
paymentStatus | string | invoice_pending. |
deliveryFeeCents | integer | The applied delivery fee (new orders only). |
Example Response
{
"reference": "hub-order-9f2a",
"orderNumbers": ["SO-10001"],
"status": "pending",
"paymentStatus": "invoice_pending",
"deliveryFeeCents": 1500
}A 200 idempotent re-fire returns the same shape without deliveryFeeCents.
Error Responses
| Status | Body (shape) | When |
|---|---|---|
201 | order payload | New order created. |
200 | order payload (no deliveryFeeCents) | Idempotent re-fire, same reference. |
404 | { "error": "Unknown distributor" } | hubCustomerId not known. |
404 | { "error": "Unknown order keys", "unknown": [...] } | An orderKey doesn't resolve. |
403 | { "error": "Distributor suspended" } | Reseller status = suspended. |
403 | { "unauthorized": [...] } | Product(s) not authorized for this distributor. |
409 | { "error": "Product not available", "unavailable": [...] } | Item fell out of the publish gate. |
409 | { "error": "Untracked variants cannot be ordered via gateway", "untracked": [...] } | manageInventory = false variant. |
409 | { "shortItems": [...] } | Insufficient stock (pre-check). |
409 | { "error": "Out of stock", "variantId": "…" } | Reservation failed in-transaction. |
409 | { "error": "Unpriced order key", "unpriced": [...] } | No resolvable cost. |
400 | { "error": "Delivery fee mismatch", "expected": 1500 } | Supplied fee ≠ server quote. |
400 | { "error": "Invalid request body" } | Schema validation failure. |
401 | { "error": "Unauthorized" } | Bad or missing API key. |
500 | { "error": "Failed to place order" } | Unhandled server error. |