# Order Post-Processing Events in the UCP Order Lifecycle

An **agentic-commerce channel** is an AI assistant such as Google Gemini that transacts through the **Universal Commerce Protocol (UCP)**. When a shopper places an order through that channel, the agent platform keeps its own current-state copy of the order, which it can surface to the shopper. To keep that copy accurate after checkout, B2C Commerce must tell the agent platform whenever the order changes.

Most changes happen **after the purchase**, in your **Order Management System (OMS)**: the order is shipped, delivered, cancelled, or returned. This guide explains how those **order post-processing events drive UCP order-lifecycle updates**—how a shipment, cancellation, or return becomes a fresh, **full-order snapshot**—carrying a cryptographic signature—delivered to the agent platform so the shopper always sees an up-to-date order.

How those events *reach* B2C Commerce depends on which OMS manages the order. There are two models:

- **[Salesforce Order Management](https://help.salesforce.com/s/articleView?id=commerce.om_impl_self_provision.htm\&type=5)** (Salesforce OMS)—B2C Commerce detects the changes and forwards them **automatically**. There is no separate integration to build. Model each delivery with a **Shipment** and its **ShipmentItem** records.
- **[A third-party OMS](/docs/commerce/b2c-commerce/guide/connect-third-party-oms.md)**—your OMS **posts** each event to a dedicated B2C Commerce API.

Which Salesforce OMS changes send an update is covered in [UCP Order Updates from Salesforce Order Management](/docs/commerce/b2c-commerce/guide/ucp-salesforce-oms-order-updates.md). How B2C Commerce builds the UCP order in each update is covered in [How the UCP Order Is Built from the Shopper Order Document](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md).

Whichever model you use, the outcome is identical: a full-order snapshot carrying a cryptographic signature, delivered asynchronously to the agent platform.

:::note
**Applies to UCP orders.** These updates are sent only for orders that originated on an agentic-commerce (UCP) channel. Orders on other channels are unaffected.
:::

## Key Concept: Every Update Is a Full-Order Snapshot

UCP requires each update to be a **complete, current-state snapshot of the order**—not an incremental delta. For every post-processing event, B2C Commerce **re-fetches the whole order** and **sends the entire order** to the agent platform.

Two kinds of entry can be attached, and the agent surface renders them differently:

| Entry kind            | Where it lives         | Represents                   | Example event types                                            |
| --------------------- | ---------------------- | ---------------------------- | -------------------------------------------------------------- |
| **Fulfillment event** | `fulfillment.events[]` | A delivery-state progression | `processing`, `shipped`, `in_transit`, `delivered`, `canceled` |
| **Adjustment**        | `adjustments[]`        | A money movement             | `cancellation`, `return`, `refund`, `credit`                   |

The `fulfillment` object is always present on every snapshot. How fulfillment history and adjustments are filled is described in [How the UCP Order Is Built from the Shopper Order Document](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md).

:::note
**Values on adjustments carry a sign (+/−).** For a cancellation, return, or refund, the money returned to the buyer and the units removed are **negative**—`totals[].amount` and `line_items[].quantity` are negative. Fulfillment-event quantities are always **non-negative** (goods delivered *to* the buyer). The sign (+/−) is **intrinsic to the value**, not something the reader derives from the `type`.
:::

## What the Platform Does vs. What You Do

| Concern                                                                                                                                | Salesforce OMS                                     | Third-party OMS                                                                                                                                         |
| -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Detect that a UCP order was shipped, canceled, or returned                                                                             | **Platform** (automatic)                           | **You** (via SCAPI)                                                                                                                                     |
| Decide the event's type, values, and sign (+/−) convention                                                                             | **Platform** (derives them from the operation)     | **You** (via SCAPI)                                                                                                                                     |
| Re-fetch the full, current order—this becomes the snapshot                                                                             | **Platform** (from Salesforce OMS)                 | **Platform** (via your retrieval hook)                                                                                                                  |
| Build the snapshot                                                                                                                     | **Platform** (rebuilds it from the order document) | **Shared**—you supply the event's content and signs (+/−) via SCAPI; the platform validates, maps them to the UCP entry, and appends it to the snapshot |
| Deliver a full-order snapshot with a cryptographic signature to the agent platform                                                     | **Platform**                                       | **Platform**                                                                                                                                            |
| Asynchronous delivery that doesn't block order operations                                                                              | **Platform**                                       | **Platform**                                                                                                                                            |
| **Fulfillment operations** (ship, mark delivered, …) that produce fulfillment events                                                   | **You** (fulfillment / operations)                 | **You** (fulfillment / operations)                                                                                                                      |
| **Adjustment actions** (cancel, return, refund) that produce adjustments—started by the **shopper**, a service rep, or your operations | **You, service rep, or shopper**                   | **You, service rep, or shopper**                                                                                                                        |

## Model A — Salesforce OMS (Automatic)

When your UCP orders are managed in **Salesforce OMS**, there is no separate integration to build. As you ship, cancel, and process returns in Salesforce OMS, B2C Commerce detects each change and forwards it to the agent platform automatically. Model each delivery with a **Shipment** and its **ShipmentItem** records.

Which quantity changes send an update, how those events are batched, and what the update contains when those shipment records are missing is covered in [UCP Order Updates from Salesforce Order Management](/docs/commerce/b2c-commerce/guide/ucp-salesforce-oms-order-updates.md#fulfillment-data-mapping). The shipment and return examples on this page show the resulting snapshot entries.

### Example — Shipment (Salesforce OMS)

A fulfillment ships two of the order's lines together. Even though multiple items ship, this is one action, so it produces a **single** UCP update—one `shipped` event listing all the shipped line items:

```json
{
  "fulfillment": {
    "events": [
      {
        "type": "shipped",
        "occurred_at": "2026-01-15T10:30:00Z",
        "line_items": [
          { "id": "10uVF0000002fn4YAA", "quantity": 1 },
          { "id": "10uVF0000002fn5ZBB", "quantity": 2 }
        ]
      }
    ]
  }
}
```

This shipment ships three units across two lines but arrives as one webhook—not three, and not one per line. The example shows only the new `shipped` entry. The full order, including the event `id` and tracking, is described in [How the UCP Order Is Built from the Shopper Order Document](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md).

### Example — Return / Refund (Salesforce OMS)

Two lines are returned together—one unit at $30.00 and two units at $20.00 each—for a $70.00 refund. This example is the **completed** return, which includes the refunded amount. The earlier return-initiated update lists the units and has no amount. As with the shipment, one action produces a **single** UCP update—one `return` adjustment listing all the returned lines:

```json
{
  "id": "adj_return_10uVF0000002fn4YAA",
  "type": "return",
  "occurred_at": "2026-01-15T10:30:00Z",
  "status": "completed",
  "line_items": [
    { "id": "10uVF0000002fn4YAA", "quantity": -1 },
    { "id": "10uVF0000002fn5ZBB", "quantity": -2 }
  ],
  "totals": [{ "type": "total", "amount": -7000 }]
}
```

Note the negative `amount` (`-7000`, that is, −$70.00 in cents) and negative quantities—money and units flowing back to the shopper. Both returned lines arrive as one webhook, not one per line. A **cancellation** looks the same with `"type": "cancellation"`.

## Model B — Third-Party OMS (the OMS Status Events API)

When your UCP orders are managed by a **third-party OMS**, B2C Commerce can't observe your OMS's internal changes. Instead, your OMS calls a dedicated API to **notify** B2C Commerce of each post-processing event. B2C Commerce then reassembles the current order (through your OMS retrieval integration), attaches the event you posted, and delivers the snapshot—carrying a cryptographic signature—to the agent platform.

Unlike the Salesforce OMS model—where B2C Commerce *derives* the event—**your OMS supplies the fully-formed event**: its type, timestamp, affected line items, tracking, totals, and signs (+/−).

:::note
**Your OMS must post every event, whatever initiated it.** A cancellation or return may be initiated by the shopper (self-service through the storefront or the agent platform), a service rep, or your operations. When a shopper cancels or returns through B2C Commerce, the platform runs your **cancel or return order hook** against your OMS—but that hook only executes the operation; it does **not** by itself notify the agent platform. Your OMS is responsible for posting the corresponding adjustment to this API so the UCP snapshot is updated.
:::

### How to Post Events

The API, its authorization, request schema, response codes, and sample request bodies are documented in **[Connect a Third-Party Order Management System (OMS)](/docs/commerce/b2c-commerce/guide/connect-third-party-oms.md#push-status-updates-to-the-platform)**, under *Push Status Updates to the Platform*, with the endpoint reference at **[`createOmsStatusEvent`](https://developer.salesforce.com/docs/commerce/commerce-api/references/orders?meta=createOmsStatusEvent)**. That guide is the authoritative reference for the endpoint; this page doesn't repeat it.

The essentials, for orientation:

- You `POST` **exactly one** `fulfillmentEvent` **or** `adjustment` per call to `oms-status-events`.
- A `fulfillmentEvent` becomes an entry in `fulfillment.events[]`; an `adjustment` becomes an entry in `adjustments[]`.
- **You author the whole event**—its type, timestamp, affected line items, tracking, totals, and **signs (+/−)**. Follow the sign (+/−) convention: quantities and amounts flowing back to the buyer are **negative**; fulfillment quantities are **non-negative**. This is the one place the platform can't derive intent for you, so the correctness of the UCP snapshot depends on the values you send.
- The endpoint is available only when your third-party OMS integration is **active for the site** (feature enabled and all order hooks registered); otherwise it returns **`409 Conflict`**.

:::note
**Inbound API vs UCP snapshot field names.** The `oms-status-events` request body uses camelCase (`occurredAt`, `lineItems`). The signed UCP snapshot uses snake_case (`occurred_at`, `line_items`). Don't copy one shape into the other.
:::

### From Your API Call to the UCP Snapshot

What is specific to *this* topic—and not covered by the OMS connection guide—is what B2C Commerce does with the event after it accepts it:

1. It **reassembles the current order** by calling your OMS `retrieve` hook (the same hook used for order look-ups), so the snapshot reflects your OMS's live state.
2. It **appends the event you posted**—the `fulfillmentEvent` to `fulfillment.events[]`, the `adjustment` to `adjustments[]`. Entries your retrieval hook already returns are preserved.
3. It **applies the cryptographic signature and delivers** the full-order snapshot to the agent platform—the same signature-protected payload the Salesforce OMS model produces.

Because the reassembly runs through your retrieval hook, the snapshot is only as current as what that hook returns. If the posted event repeats a step that hook already returns, see [Removing Duplicate Events](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md#removing-duplicate-events).

## What Arrives at the Agent Platform

Every update is one delivery containing the **full order**, with:

- the always-present **`fulfillment`** object (including any `events[]` such as `shipped`), and
- any **`adjustments[]`** entry for the return or cancellation that triggered this update. Earlier adjustments aren't included. How those entries are limited is described in [How the UCP Order Is Built from the Shopper Order Document](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md).

Delivery is:

- **Signature-protected**—each webhook carries a cryptographic signature (HTTP Message Signatures, RFC 9421) so the agent platform can verify it came from B2C Commerce. Saving UCP settings in Business Manager generates the signing keys advertised on the [business profile](/docs/commerce/b2c-commerce/guide/ucp-configuration.md#security).
- **Asynchronous**—sending happens off to the side and never blocks or slows your order operations.

To mutate the payload immediately before signed delivery, implement `sfcc.ucp.orderWebhook.v1.modifyEventPayload`. If that hook fails or returns a non-OK status, the webhook is retried. See [Business Profile and Order Webhooks](/docs/commerce/b2c-commerce/guide/ucp-implementation-considerations.md#business-profile-and-order-webhooks).

## Related Reading

- [UCP Order Updates from Salesforce Order Management](/docs/commerce/b2c-commerce/guide/ucp-salesforce-oms-order-updates.md)—which Salesforce OMS quantity changes send a UCP update
- [How the UCP Order Is Built from the Shopper Order Document](/docs/commerce/b2c-commerce/guide/ucp-order-built-from-shopper-order.md)—how each update is assembled from the order document
- [Configuration and Discovery](/docs/commerce/b2c-commerce/guide/ucp-configuration.md)—Business Manager UCP settings, OMS options, and signing keys
- [Implementation Considerations](/docs/commerce/b2c-commerce/guide/ucp-implementation-considerations.md#business-profile-and-order-webhooks)—order webhook hook, including `modifyEventPayload`
- [Connect a Third-Party Order Management System (OMS)](/docs/commerce/b2c-commerce/guide/connect-third-party-oms.md)—building and registering the order hooks the third-party model depends on, and the `oms-status-events` API
- [UCP order specification](https://ucp.dev/latest/specification/order/)
