Update an order

Orders rarely stay perfect after creation. Inventory changes, operations teams attach internal metadata after review, and approved quotes get revised after an invoice has already gone out. This guide shows how to use Update an order for the three update flows most teams hit in production without losing payment context or order history.


Prerequisites

  • An existing order ID in a mutable state such as preparing or requires_payment
  • Familiarity with the Order lifecycle
  • Access to the Update an order API reference
  • A server-side secret key for authenticated API calls

How orders/update behaves

Reach for Update an order when you need to:

  1. Replace the order's full line item set before payment starts
  2. Refresh order-level custom_data without disturbing payment state
  3. Revise a sealed order and deliberately reseal it

The endpoint always returns the full order object. If the order is still open, Commerce applies the change directly. If the order is already sealed and your change affects economics or payment configuration, you must make the seal decision explicit with finalize. Metadata-only custom_data updates are different: Commerce can apply them without reopening or resealing by itself. The examples below use direct HTTPS calls so you can adopt the endpoint immediately from any stack.


Scenario 1: Replace line items before payment starts

This is the most common order update flow. A customer changes quantities, an item goes out of stock, or you need to add a manual fee before charging. Send the complete new line_items array—Commerce replaces the previous collection instead of merging it.

Replace line items

POST
/orders/update
curl https://api.zebo.dev/orders/update \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "or_4Jv9wK2LmQ8rT6xP1nY5sC3dF7hB0uA",
    "number": "ORDER-2025-041-REV1",
    "line_items": [
      {
        "type": "product",
        "product": {
          "name": "Warehouse-picked sneaker",
          "type": "physical",
          "quantity": 2,
          "price": { "currency": "ghs", "value": 9500 }
        }
      },
      {
        "type": "fee",
        "fee": {
          "label": "Delivery fee",
          "amount": { "currency": "ghs", "value": 1500 }
        }
      }
    ]
  }'

After the update:

  • Commerce replaces the previous line items completely.
  • line_item_group.total and payment.amount are recalculated from the new items.
  • The order remains editable because you did not ask Commerce to seal it.

Scenario 2: Refresh order-level custom data

Many teams update orders after creation just to attach operational metadata: a review channel, approver identity, fulfillment lane, or internal note that should travel with the order. Send the full replacement custom_data object when you want to refresh those fields. This is a metadata-only mutation, so it does not require reopen or reseal by itself.

Update custom data

POST
/orders/update
curl https://api.zebo.dev/orders/update \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "or_aR7mK4qP9dT2xW6nC1yV8sJ5bL0fH3u",
    "custom_data": {
      "channel": "ops_review",
      "edited_by": "merx",
      "priority": "high"
    }
  }'

After the update:

  • Commerce replaces the top-level custom_data object with the new one you provided.
  • The order's economic state stays unchanged: totals, line items, and payment amount are preserved.
  • Because this is metadata-only, you can use it without reopening a sealed order or resealing it again.

Use this flow for internal annotations that should travel with the order record but must not change what the customer pays. Typical examples include review queues, fulfillment lanes, campaign attribution, and dashboard-only notes.


Scenario 3: Revise a sealed order and reseal it in one request

This is the high-friction case that matters most in production. You already finalized the order and maybe even sent the invoice, then a customer negotiates a change before payment completes. Send the revised fields together with finalize: true and Commerce will reopen the sealed order internally, apply the changes, and reseal it before returning the updated object.

Revise and reseal

POST
/orders/update
curl https://api.zebo.dev/orders/update \
  -H "Authorization: Bearer $COMMERCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "or_zT5mQ8wL2pR7vK1xN4cD9sF6hB3uJ0y",
    "number": "QUOTE-2025-009-REV2",
    "finalize": true,
    "line_items": [
      {
        "type": "product",
        "product": {
          "name": "Annual support retainer",
          "type": "service",
          "quantity": 1,
          "price": { "currency": "ghs", "value": 120000 }
        }
      },
      {
        "type": "fee",
        "fee": {
          "label": "Onboarding workshop",
          "amount": { "currency": "ghs", "value": 15000 }
        }
      }
    ]
  }'

After the update:

  • Commerce recalculates the order total and payment amount from the revised items.
  • sealed_at is refreshed because the order was sealed again.
  • invoice is regenerated so the latest hosted checkout and PDF reflect the revised commercial terms.

If you want the order to stay open for more manual edits, send the same mutation with finalize: false instead. Commerce will reopen the sealed order and clear the active invoice until you seal it again with Finalize an order or another Update an order call.


Was this page helpful?