Integrating with Extend's Order API
This guide explains how to use the Extend Orders APIs effectively, with a focus on the recommended Orders Upsert endpoint, versioning, payload structure, and common pitfalls to avoid.
Overview
Extend's Orders Upsert API provides a single endpoint for creating and updating order records within Extend's system. All orders — whether they include Extend Product Protection, Category-based Protection (OBC), Shipping Protection, or no protection at all — can be sent through this API.
The endpoint uses the transactionId as a unique key: if an order with that transactionId already exists, it will be updated; otherwise, a new order is created. Each request should contain a full order snapshot (all customer details and line items), with only field-level changes to reflect updates.
Key Concepts
- Full Snapshot Model: Every API call sends the complete, current state of the order. The API automatically detects additions and deletions by comparing the current request to the previous snapshot.
- Idempotent by Design: Sending the same snapshot multiple times produces the same result. Use this to your advantage for retry logic.
- Contract Creation on Fulfillment: Extend generates protection contracts (identified by
contractId) only when line items are marked as fulfilled via thefulfilledQuantityfield.
Authentication
Before making requests, authenticate via Extend's Authentication Guide to obtain your API credentials.
Category Orders (Recommended)
Best Practice: Category Orders are Extend's recommended and prescriptive approach for integrating protection plans. Category Orders allow a single contract to cover multiple products within the same product category, simplifying contract management, improving operational efficiency, and providing a better customer experience.
How Category Orders Work
Category Orders use a category_contract line item type that groups multiple products under a single protection contract based on their product category. Key characteristics:
- One contract covers multiple products within the same category
- Each product maintains its own coverage date and limit of liability (LoL), but all share the same
contractId - Multiple category contracts per order are supported — for example, one contract for furniture items and another for electronics
- Extend differentiates category contracts based on the
plan.idprovided in the request
Creating a Category Order
The following example creates an order with two furniture products (8 Dining Chairs and 1 Dining Extension Table) covered under a single 5-year furniture protection category contract.
Request:
PUT /orders
{
"currency": "USD",
"transactionId": "972868770",
"transactionDate": 1748476800000,
"storeId": "{{your-extend-store-id}}",
"merchantCustomerId": "Customer1234",
"poNumber": "PO4567",
"saleOrigin": {
"agentId": "Sam Smith",
"channel": "store",
"locationId": "Store number 17519",
"storeId": "{{your-extend-store-id}}"
},
"customer": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "1234567899",
"billingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
},
"shippingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
}
},
"lineItems": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg",
"mfrWarranty": {
"labor": 6,
"parts": 6,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 8,
"fulfilledQuantity": 0
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"product": {
"id": "D984-02",
"title": "Dining Extension Table",
"category": "Tables",
"listPrice": 99999,
"purchasePrice": 67999,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-table.jpg",
"mfrWarranty": {
"labor": 12,
"parts": 12,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"type": "category_contract",
"lineItemTransactionId": "972868770-A17-FURNID-5y",
"quantity": 1,
"fulfilledQuantity": 0,
"plan": {
"id": "A17-FURNID-5y",
"purchaseDate": 1748476800000,
"purchasePrice": 42999
},
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
}
]
}
]
}Key points about this payload:
fulfilledQuantityis0for all line items at order creation (no items have shipped yet)- The
category_contractline item hasquantity: 1andfulfilledQuantity: 0 - The
coveredProductsarray lists every product covered under this category contract, with theirlineItemTransactionId,productId, andquantity - The
plan.idvalue (A17-FURNID-5y) identifies the specific category protection plan plan.purchasePriceis the total cost of the category protection plan (not the individual product prices)
Fulfilling a Category Order
When products in a category order are fulfilled (shipped/invoiced), update the fulfilledQuantity at both the product level and the category contract level.
Important: Once the first product within a category contract is fulfilled, set the category contract's
fulfilledQuantityto1. This triggers Extend to generate thecontractIdin the response. OmittingfulfilledQuantityat the category contract level may cause invoicing discrepancies.
Partial Fulfillment — Shipment 1 (Chairs shipped, Table pending)
PUT /orders
{
"currency": "USD",
"transactionId": "972868770",
"transactionDate": 1748476800000,
"storeId": "{{your-extend-store-id}}",
"merchantCustomerId": "Customer1234",
"poNumber": "PO4567",
"saleOrigin": {
"agentId": "Sam Smith",
"channel": "store",
"locationId": "Store number 17519",
"storeId": "{{your-extend-store-id}}"
},
"customer": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "1234567899",
"billingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
},
"shippingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
}
},
"lineItems": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg",
"mfrWarranty": {
"labor": 6,
"parts": 6,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 8,
"fulfilledQuantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"product": {
"id": "D984-02",
"title": "Dining Extension Table",
"category": "Tables",
"listPrice": 99999,
"purchasePrice": 67999,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-table.jpg",
"mfrWarranty": {
"labor": 12,
"parts": 12,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"type": "category_contract",
"lineItemTransactionId": "972868770-A17-FURNID-5y",
"quantity": 1,
"fulfilledQuantity": 1,
"plan": {
"id": "A17-FURNID-5y",
"purchaseDate": 1748476800000,
"purchasePrice": 42999
},
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
}
]
}
]
}What changed:
- Dining Chair
fulfilledQuantityupdated from0→8(all 8 chairs shipped) - Category contract
fulfilledQuantityupdated from0→1(first product fulfilled triggers contract creation) - Dining Extension Table
fulfilledQuantityremains0(not yet shipped) - All other fields remain identical — always send the full snapshot
Full Fulfillment — Shipment 2 (Table now also shipped)
PUT /orders
{
"currency": "USD",
"transactionId": "972868770",
"transactionDate": 1748476800000,
"storeId": "{{your-extend-store-id}}",
"merchantCustomerId": "Customer1234",
"poNumber": "PO4567",
"saleOrigin": {
"agentId": "Sam Smith",
"channel": "store",
"locationId": "Store number 17519",
"storeId": "{{your-extend-store-id}}"
},
"customer": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "1234567899",
"billingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
},
"shippingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
}
},
"lineItems": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg",
"mfrWarranty": {
"labor": 6,
"parts": 6,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 8,
"fulfilledQuantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"product": {
"id": "D984-02",
"title": "Dining Extension Table",
"category": "Tables",
"listPrice": 99999,
"purchasePrice": 67999,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-table.jpg",
"mfrWarranty": {
"labor": 12,
"parts": 12,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 1,
"fulfilledQuantity": 1
},
{
"type": "category_contract",
"lineItemTransactionId": "972868770-A17-FURNID-5y",
"quantity": 1,
"fulfilledQuantity": 1,
"plan": {
"id": "A17-FURNID-5y",
"purchaseDate": 1748476800000,
"purchasePrice": 42999
},
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
}
]
}
]
}What changed:
- Dining Extension Table
fulfilledQuantityupdated from0→1 - Category contract
fulfilledQuantityremains1(already triggered — it only needs to transition from 0 to 1 once)
Adding Products to a Category Order
To add a new product to an existing category order, include the new product line item and update the coveredProducts array on the category contract.
In this example, we add 4 Accent Chairs to the existing furniture category contract:
PUT /orders
{
"currency": "USD",
"transactionId": "972868770",
"transactionDate": 1748476800000,
"storeId": "{{your-extend-store-id}}",
"merchantCustomerId": "Customer1234",
"poNumber": "PO4567",
"saleOrigin": {
"agentId": "Sam Smith",
"channel": "store",
"locationId": "Store number 17519",
"storeId": "{{your-extend-store-id}}"
},
"customer": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "1234567899",
"billingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
},
"shippingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
}
},
"lineItems": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg",
"mfrWarranty": {
"labor": 6,
"parts": 6,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 8,
"fulfilledQuantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"product": {
"id": "D984-02",
"title": "Dining Extension Table",
"category": "Tables",
"listPrice": 99999,
"purchasePrice": 67999,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-table.jpg",
"mfrWarranty": {
"labor": 12,
"parts": 12,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 1,
"fulfilledQuantity": 1
},
{
"lineItemTransactionId": "972868770_100_D737-03",
"product": {
"id": "D737-03",
"title": "Accent Chair",
"category": "Chairs",
"listPrice": 12000,
"purchasePrice": 8500,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/accent-chair.jpg",
"mfrWarranty": {
"labor": 6,
"parts": 6,
"url": "https://www.brand.com/warranty"
}
},
"quantity": 4,
"fulfilledQuantity": 0
},
{
"type": "category_contract",
"lineItemTransactionId": "972868770-A17-FURNID-5y",
"quantity": 1,
"fulfilledQuantity": 1,
"plan": {
"id": "A17-FURNID-5y",
"purchaseDate": 1748476800000,
"purchasePrice": 42999
},
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
},
{
"lineItemTransactionId": "972868770_100_D737-03",
"productId": "D737-03",
"quantity": 4
}
]
}
]
}What changed:
- New Accent Chair line item added with unique
lineItemTransactionId:972868770_100_D737-03 coveredProductsarray updated to include the new product- All existing line items remain in the payload (full snapshot)
Increasing Quantity on a Category Order
To increase the quantity of an existing product, update the quantity field on the product line item and the corresponding entry in coveredProducts.
Example: Increasing Dining Chairs from 8 to 10:
// Within lineItems array — product line item
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg"
},
"quantity": 10,
"fulfilledQuantity": 8
}
// Within the category_contract's coveredProducts array
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 10
}What changed:
- Product
quantityupdated from8→10 coveredProductsentryquantityupdated from8→10fulfilledQuantityremains at8(only 8 have shipped so far)
Refunding a Category Order
Full Order Refund
To refund all contracts associated with an order, set the order-level status to "refunded":
PUT /orders
{
"currency": "USD",
"transactionId": "972868770",
"transactionDate": 1748476800000,
"storeId": "{{your-extend-store-id}}",
"status": "refunded",
"merchantCustomerId": "Customer1234",
"poNumber": "PO4567",
"saleOrigin": {
"agentId": "Sam Smith",
"channel": "store",
"locationId": "Store number 17519",
"storeId": "{{your-extend-store-id}}"
},
"customer": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "1234567899",
"billingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
},
"shippingAddress": {
"address1": "535 Mission Street",
"address2": "11th Floor",
"city": "San Francisco",
"countryCode": "US",
"postalCode": "94526",
"province": "CA"
}
},
"lineItems": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg"
},
"quantity": 8,
"fulfilledQuantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"product": {
"id": "D984-02",
"title": "Dining Extension Table",
"category": "Tables",
"listPrice": 99999,
"purchasePrice": 67999,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-table.jpg"
},
"quantity": 1,
"fulfilledQuantity": 1
},
{
"type": "category_contract",
"lineItemTransactionId": "972868770-A17-FURNID-5y",
"quantity": 1,
"fulfilledQuantity": 1,
"plan": {
"id": "A17-FURNID-5y",
"purchaseDate": 1748476800000,
"purchasePrice": 42999
},
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 8
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
}
]
}
]
}What changed:
- Added
"status": "refunded"at the order level - This refunds all associated contracts for the entire order
Partial Refund — Reducing Quantity
To partially refund a product, reduce its quantity and update the coveredProducts accordingly. The API will refund the difference.
Example: Reducing Dining Chairs from 8 to 6 (refunding 2 chairs):
// Product line item — reduced quantity
{
"lineItemTransactionId": "972868770_100_D736-01",
"product": {
"id": "D736-01",
"title": "Dining Chair",
"category": "Chairs",
"listPrice": 15000,
"purchasePrice": 10200,
"purchaseDate": 1748476800000,
"imageUrl": "https://example.com/dining-chair.jpg"
},
"quantity": 6,
"fulfilledQuantity": 6
}
// Updated coveredProducts in the category_contract
"coveredProducts": [
{
"lineItemTransactionId": "972868770_100_D736-01",
"productId": "D736-01",
"quantity": 6
},
{
"lineItemTransactionId": "972868770_10_D984-02",
"productId": "D984-02",
"quantity": 1
}
]Partial Refund — Removing a Product
To fully remove a product from the order, omit it from the lineItems array and remove it from the coveredProducts array. The API will cancel or refund any existing contracts for the removed line items.
Alternative: Product Protection Orders
Product Protection is a simpler alternative to Category Orders that falls under the same product protection umbrella. While Category Orders (above) are the recommended approach, Product Protection may be appropriate when each product requires its own independent contract — for example, when products span unrelated categories or when your system cannot support the
category_contractline item structure. The core API mechanics (full snapshots,transactionId,fulfilledQuantity) work identically; the difference is in how contracts are structured.
Product Protection orders cover individual products with their own dedicated protection plan. Each product-plan pairing creates a separate contract — unlike Category Orders, which group multiple products under a single contract.
Creating a Product Protection Order
The following example creates an order with two products, each paired with its own protection plan.
PUT /orders
{
"currency": "USD",
"transactionId": "PP-100200300",
"storeId": "{{your-extend-store-id}}",
"customer": {
"email": "[email protected]",
"name": "John Doe",
"phone": "5551234567",
"billingAddress": {
"address1": "100 Main Street",
"city": "Austin",
"countryCode": "US",
"postalCode": "78701",
"province": "TX"
},
"shippingAddress": {
"address1": "100 Main Street",
"city": "Austin",
"countryCode": "US",
"postalCode": "78701",
"province": "TX"
}
},
"total": 12198,
"lineItems": [
{
"lineItemTransactionId": "PP-100200300_Line1",
"product": {
"id": "REF-2355",
"title": "Standing Desk",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/standing-desk.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"lineItemTransactionId": "PP-100200300_Line2",
"product": {
"id": "REF-4580",
"title": "Ergonomic Chair",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/ergonomic-chair.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
}
]
}Key points:
- Each product line item includes a
planobject directly — no separatecategory_contractline item is needed - Each product-plan pair will generate its own
contractIdupon fulfillment fulfilledQuantitystarts at0for newly created orders
Fulfilling a Product Protection Order
Partial Fulfillment — Product 1 ships
Update fulfilledQuantity for the shipped product only:
PUT /orders
{
"currency": "USD",
"transactionId": "PP-100200300",
"storeId": "{{your-extend-store-id}}",
"customer": {
"email": "[email protected]",
"name": "John Doe",
"phone": "5551234567",
"billingAddress": {
"address1": "100 Main Street",
"city": "Austin",
"countryCode": "US",
"postalCode": "78701",
"province": "TX"
},
"shippingAddress": {
"address1": "100 Main Street",
"city": "Austin",
"countryCode": "US",
"postalCode": "78701",
"province": "TX"
}
},
"total": 12198,
"lineItems": [
{
"lineItemTransactionId": "PP-100200300_Line1",
"product": {
"id": "REF-2355",
"title": "Standing Desk",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/standing-desk.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 1
},
{
"lineItemTransactionId": "PP-100200300_Line2",
"product": {
"id": "REF-4580",
"title": "Ergonomic Chair",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/ergonomic-chair.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
}
]
}What changed:
- Standing Desk
fulfilledQuantityupdated from0→1 - The API response will include a
contractIdfor the Standing Desk's protection plan - Ergonomic Chair remains at
fulfilledQuantity: 0
Full Fulfillment — Product 2 ships
Send the same full snapshot with both products' fulfilledQuantity set to 1. The API response will now include contractId values for both products.
Refunding a Product Protection Order
Full Order Refund
Add "status": "refunded" at the order level (same pattern as Category Orders):
{
"transactionId": "PP-100200300",
"status": "refunded",
// ... full order snapshot ...
}Partial Refund — Single Line Item
To refund a specific product, either reduce its quantity or omit it entirely from the lineItems array. The API will refund or cancel the associated contract.
Shipping Protection Orders
Shipping Protection covers products against loss, damage, or theft during transit. It is added as a dedicated line item in the order with tracking and shipment details.
Creating an Order with Shipping Protection
The following example creates an order with two products, Product Protection plans for each, and a Shipping Protection line item covering both products.
PUT /orders
{
"currency": "USD",
"transactionId": "SP-500600700",
"storeId": "{{your-extend-store-id}}",
"customer": {
"email": "[email protected]",
"name": "Sarah Jones",
"phone": "5559876543",
"billingAddress": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
},
"shippingAddress": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
}
},
"total": 20299,
"lineItems": [
{
"lineItemTransactionId": "SP-500600700_Line1",
"product": {
"id": "REF-2355",
"title": "Standing Desk",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/standing-desk.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"lineItemTransactionId": "SP-500600700_Line2",
"product": {
"id": "REF-4580",
"title": "Ergonomic Chair",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/ergonomic-chair.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"lineItemTransactionId": "SP-500600700_ShippingProtection",
"quoteId": "45005545-94c9-41a6-ade1-63514aa93f79",
"shipmentInfo": []
}
]
}Key points about Shipping Protection:
- The Shipping Protection line item uses a
quoteId(obtained when the customer purchases Shipping Protection at checkout) — this identifies the specific coverage quote shipmentInfois an empty array at order creation because tracking details are typically not available yet- Shipment details are added in subsequent updates once products ship
Updating Shipment Tracking — Shipment 1
Once the first product ships, update the order to include tracking information in the shipmentInfo array:
PUT /orders
{
"currency": "USD",
"transactionId": "SP-500600700",
"storeId": "{{your-extend-store-id}}",
"customer": {
"email": "[email protected]",
"name": "Sarah Jones",
"phone": "5559876543",
"billingAddress": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
},
"shippingAddress": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
}
},
"total": 20299,
"lineItems": [
{
"lineItemTransactionId": "SP-500600700_Line1",
"product": {
"id": "REF-2355",
"title": "Standing Desk",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/standing-desk.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 1
},
{
"lineItemTransactionId": "SP-500600700_Line2",
"product": {
"id": "REF-4580",
"title": "Ergonomic Chair",
"category": "Furniture",
"listPrice": 9400,
"purchasePrice": 9400,
"imageUrl": "https://example.com/ergonomic-chair.jpg"
},
"plan": {
"id": "A1-FURIND-3y",
"purchasePrice": 699
},
"quantity": 1,
"fulfilledQuantity": 0
},
{
"lineItemTransactionId": "SP-500600700_ShippingProtection",
"quoteId": "45005545-94c9-41a6-ade1-63514aa93f79",
"shipmentInfo": [
{
"productIds": ["REF-2355"],
"shipmentDate": 1684427850000,
"shippingProvider": "usps",
"trackingId": "usps-9400111899223100001234",
"trackingUrl": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223100001234",
"source": {
"address1": "500 Warehouse Blvd",
"city": "Dallas",
"countryCode": "US",
"postalCode": "75201",
"province": "TX"
},
"destination": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
}
}
]
}
]
}What changed:
- Standing Desk
fulfilledQuantityupdated from0→1 shipmentInfonow contains a shipment record with tracking details for the Standing DeskproductIdsreferences which product(s) are in this shipmenttrackingIdis used by the API to identify and manage individual shipments
Adding a Second Shipment
When the second product ships, add a new entry to the shipmentInfo array while retaining all previous shipment entries:
// Shipping Protection line item with both shipments
{
"lineItemTransactionId": "SP-500600700_ShippingProtection",
"quoteId": "45005545-94c9-41a6-ade1-63514aa93f79",
"shipmentInfo": [
{
"productIds": ["REF-2355"],
"shipmentDate": 1684427850000,
"shippingProvider": "usps",
"trackingId": "usps-9400111899223100001234",
"trackingUrl": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223100001234",
"source": {
"address1": "500 Warehouse Blvd",
"city": "Dallas",
"countryCode": "US",
"postalCode": "75201",
"province": "TX"
},
"destination": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
}
},
{
"productIds": ["REF-4580"],
"shipmentDate": 1684514250000,
"shippingProvider": "fedex",
"trackingId": "fedex-794644790132",
"trackingUrl": "https://www.fedex.com/fedextrack/?trknbr=794644790132",
"source": {
"address1": "500 Warehouse Blvd",
"city": "Dallas",
"countryCode": "US",
"postalCode": "75201",
"province": "TX"
},
"destination": {
"address1": "200 Oak Avenue",
"city": "Round Rock",
"countryCode": "US",
"postalCode": "78664",
"province": "TX"
}
}
]
}Critical: If you omit a previously sent shipment entry from the
shipmentInfoarray, the API will delete that shipment record. Always include all existing shipment entries when adding new ones.
Shipment Management via trackingId
The API uses trackingId within the shipmentInfo array to determine how to handle each shipment entry:
- New
trackingId: Creates a new shipment record - Existing
trackingIdwith updated details: Updates the existing shipment record - Missing
trackingId(previously sent but not included): Deletes that shipment record
Key Considerations
TransactionId and LineItemTransactionId
These two identifiers are the backbone of the Orders Upsert API:
transactionId(order level): Your order number. The API uses this to match incoming requests to existing orders.lineItemTransactionId(line item level): Your order item number. Must be unique within an order.
Both are set at order creation and must not change in subsequent updates. If your OMS/ERP system does not generate stable identifiers by default, concatenate existing fields to create a unique, consistent value. Contact Extend if this is not possible in your system.
For products with multiple quantities, all units of the same SKU share the same lineItemTransactionId — use the quantity and fulfilledQuantity fields to track individual units.
Full Order Snapshot Requirement
Every API request must contain the complete, current state of the order — all customer details, all line items (including unchanged ones), and all shipment records.
The API determines changes by comparing the incoming snapshot to the previous one:
- New
lineItemTransactionId→ line item is added - Missing
lineItemTransactionId(previously present) → line item is cancelled/refunded - Changed field values on an existing line item → line item is updated
This means you cannot send "partial" updates with only the changed fields. The tradeoff is simplicity: you always send the same complete order payload, just with updated field values.
ContractId Response
When a line item's fulfilledQuantity transitions from 0 to a positive number, the API response includes a contractId for the associated protection plan. Store these values in your system for traceability, reconciliation, and claims management.
For Category Orders, the contractId is returned when the category_contract line item's fulfilledQuantity changes from 0 to 1 (triggered by the first product fulfillment within that contract).
For Product Protection, each product line item generates its own contractId independently upon fulfillment.
For Shipping Protection, a contractId is returned for the entire order's shipping protection coverage when applicable.
Combining Protection Types
Orders can include multiple protection types simultaneously. For example, you might have Category Orders for product protection combined with a Shipping Protection line item in the same order. The API handles each protection type independently based on the line item structure provided.
Field Reference
| Field | Level | Type | Description |
|---|---|---|---|
transactionId | Order | String | Unique order identifier (order number). Used as the key for creates and updates. |
storeId | Order | UUID | Your Extend store identifier. |
currency | Order | String | Currency code (e.g., "USD"). |
total | Order | Number | Total order amount in cents. |
status | Order | String | Set to "refunded" to refund the entire order. |
transactionDate | Order | Timestamp | Order creation date in epoch milliseconds. |
merchantCustomerId | Order | String | Your internal customer identifier. |
poNumber | Order | String | Purchase order number. |
lineItemTransactionId | Line Item | String | Unique line item identifier within the order. Immutable after creation. |
type | Line Item | String | "category_contract" for category orders. Omit for standard product protection. |
quantity | Line Item | Number | Total quantity ordered. |
fulfilledQuantity | Line Item | Number | Quantity fulfilled/shipped. Set to 0 at creation. |
product.id | Product | String | Your product SKU/identifier. |
product.category | Product | String | Product category (e.g., "Furniture", "Electronics"). |
product.purchasePrice | Product | Number | Product purchase price in cents. Drives limit of liability. |
product.listPrice | Product | Number | Product list/retail price in cents. |
plan.id | Plan | String | Extend protection plan identifier. |
plan.purchasePrice | Plan | Number | Protection plan price in cents. |
coveredProducts | Category Contract | Array | Products covered under this category contract. Required for type: "category_contract". |
quoteId | Shipping Protection | UUID | Quote identifier for Shipping Protection. |
shipmentInfo | Shipping Protection | Array | Array of shipment tracking records. |
shipmentInfo[].trackingId | Shipment | String | Tracking number. Used for shipment add/update/delete logic. |
shipmentInfo[].shippingProvider | Shipment | String | Carrier name (e.g., "usps", "fedex"). |
shipmentInfo[].shipmentDate | Shipment | Timestamp | Ship date in epoch milliseconds. |
shipmentInfo[].productIds | Shipment | Array | Product IDs included in this shipment. |
Best Practices Summary
- Use Category Orders as your default approach — they simplify contract management by covering multiple products under a single contract per category.
- Always send full order snapshots — never attempt partial updates. Include every line item and shipment record in every request.
- Treat
transactionIdandlineItemTransactionIdas immutable — set them at creation and never change them. - Track
fulfilledQuantityat all levels — for Category Orders, update both the product lines and thecategory_contractline. Failure to do so may impact invoicing. - Include all previous shipment entries — when adding new shipments to Shipping Protection, always retain prior entries or they will be deleted.
- Store
contractIdvalues — save the returned contract IDs for traceability, reconciliation, and claims reference. - Use
trackingIdfor shipment lifecycle management — the API uses this value to determine whether to add, update, or remove shipment records. - Contact Extend for edge cases — if your system cannot maintain stable identifiers or has unique constraints, reach out for guidance.
Updated about 7 hours ago