Claude
Skills
Sign in
Back

marketplace-fulfillment

Included with Lifetime
$97 forever

Apply when implementing fulfillment, invoice, or tracking logic for VTEX marketplace seller connectors. Covers the External Seller fulfillment protocol: fulfillment simulation (checkout and indexation), order placement with reservation id, order dispatch (authorize fulfillment), OMS invoice and tracking APIs, and partial invoicing. Use for seller-side services that must answer within the simulation SLA and integrate with VTEX marketplace order management.

Data & Analytics

What this skill does


# Fulfillment, simulation, orders & OMS follow-up

## When this skill applies

Use this skill when building an **External Seller** integration: VTEX forwards availability, shipping, checkout simulation, and order placement to **your** fulfillment base URL, and you call the marketplace **OMS** APIs for invoice and tracking after dispatch.

- Implementing **`POST /pvt/orderForms/simulation`** (indexation and/or checkout — with or without customer context)
- Implementing **`POST /pvt/orders`** (order placement — create **reservation**; return **`orderId`** = reservation id in your system)
- Handling **`POST /pvt/orders/{sellerOrderId}/fulfill`** (order dispatch after approval — path uses the **same** id you returned as `orderId` at placement)
- Sending invoice notifications via `POST /api/oms/pvt/orders/{marketplaceOrderId}/invoice` (marketplace order id in the path)
- Updating tracking via `PATCH /api/oms/pvt/orders/{marketplaceOrderId}/invoice/{invoiceNumber}`
- Implementing partial invoicing for split shipments

Do not use this skill for:
- Catalog or SKU synchronization (see `marketplace-catalog-sync`)
- Order event consumption via Feed/Hook (see `marketplace-order-hook`)
- General API rate limiting (see `marketplace-rate-limiting`)

## Decision rules

### External Seller protocol (implemented on the seller host)

- **Fulfillment simulation** — `POST /pvt/orderForms/simulation`. VTEX calls it during **product indexation** and during **checkout**. Requests may include **only** `items` (and optionally query params), or the **full** checkout context: `items`, `postalCode`, `country`, `clientProfileData`, `shippingData`, `selectedSla`, etc. Without postal code / profile (typical indexation), the response must still state whether each item is **available**. With full context, return **`items`**, **`logisticsInfo`** (one entry per requested item), **`postalCode`**, **`country`**, and set **`allowMultipleDeliveries`** to `true` as required by the contract. **`items[].id`** is the **seller SKU id**; **`items[].seller`** is the **seller id** on the marketplace account.
- **Response shape** — Each `logisticsInfo[]` row aligns with a requested item (`itemIndex`). Include **`slas[]`** with all delivery options (home delivery and **pickup-in-point** when applicable), **`deliveryChannels[]`** with per-channel stock, **`shipsTo`**, and **`stockBalance`**. SLA fields include `price` (shipping per item, in cents), `shippingEstimate` / `shippingEstimateDate` (e.g. `5bd`, `30m`). Pickup SLAs must include **`pickupStoreInfo`** (address, `friendlyName`, etc.).
- **SLA** — The simulation handler must respond within **2.5 seconds** or the offer is treated as unavailable.
- **Order placement** — `POST /pvt/orders` with a **JSON array** of orders. For each order, create a **reservation** in your system. The **response** must be the same structure with an added **`orderId`** on each order: that value is your **reservation id** and becomes the **`sellerOrderId`** in later protocol calls (e.g. authorize fulfillment path parameter).
- **Order dispatch (authorize fulfillment)** — After marketplace approval, VTEX calls `POST /pvt/orders/{sellerOrderId}/fulfill` where **`sellerOrderId`** equals the **`orderId`** you returned at placement. Body includes **`marketplaceOrderId`** and **`marketplaceOrderGroup`**. Convert the reservation to a firm order in your system; response body includes `date`, `marketplaceOrderId`, **`orderId`** (seller reference), `receipt`.

### OMS APIs (seller → marketplace)

- Send invoices via `POST /api/oms/pvt/orders/{marketplaceOrderId}/invoice`. Required fields: `type`, `invoiceNumber`, `invoiceValue` (in cents), `issuanceDate`, and `items` array. Path **`marketplaceOrderId`** is the VTEX marketplace order id, not your reservation id.
- Use `type: "Output"` for sales invoices (shipment) and `type: "Input"` for return invoices.
- Send tracking **separately** after the carrier provides it, using `PATCH /api/oms/pvt/orders/{marketplaceOrderId}/invoice/{invoiceNumber}`.
- For split shipments, send **one invoice per package** with only the items in that package. Each `invoiceValue` must reflect only its items.
- Once an order is invoiced, it cannot be canceled without first sending a return invoice (`type: "Input"`).
- The fulfillment simulation endpoint must respond within **2.5 seconds** or the product is considered unavailable.

**Architecture / data flow (high level)**:

```text
VTEX Checkout / indexation          External Seller                    VTEX OMS (marketplace)
       │                                   │                                   │
       │── POST /pvt/orderForms/simulation ▶│  Price, stock, SLAs               │
       │◀── 200 + items + logisticsInfo ───│                                   │
       │                                   │                                   │
       │── POST /pvt/orders (array) ───────▶│  Create reservation               │
       │◀── same + orderId (reservation) ─│                                   │
       │                                   │                                   │
       │── POST /pvt/orders/{id}/fulfill ──▶│  Commit / pick pack               │
       │◀── date, marketplaceOrderId, ... ─│                                   │
       │                                   │── POST .../invoice ────────────────▶│
       │                                   │── PATCH .../invoice/{n} ─────────▶│
```

## Hard constraints

### Constraint: Marketplace order ID in OMS paths

Any `{orderId}` in **`/api/oms/pvt/orders/{orderId}/...`** MUST be the **VTEX marketplace order id** (OMS), not the **`orderId`** you returned at **`POST /pvt/orders`** (reservation id). Map `marketplaceOrderId` from the protocol (placement payload, fulfill body, or events) before calling invoice or tracking APIs.

**Why this matters**

Using the reservation id in OMS URLs fails to match the marketplace order; invoices and tracking never attach to the customer order.

**Detection**

If the same variable is used for both `POST /pvt/orders` response `orderId` and `POST .../oms/.../invoice` without mapping → STOP.

**Correct**

```typescript
// reservationId from your POST /pvt/orders response; marketplaceOrderId from VTEX payload
await omsClient.post(`/api/oms/pvt/orders/${marketplaceOrderId}/invoice`, payload);
```

**Wrong**

```typescript
await omsClient.post(`/api/oms/pvt/orders/${reservationId}/invoice`, payload);
```

---

### Constraint: Fulfillment simulation contract and latency

The seller MUST implement **`POST /pvt/orderForms/simulation`** to return a valid **`items`** array for every request. When the request includes checkout context (e.g. `postalCode`, `clientProfileData`, `shippingData`), the response MUST include aligned **`logisticsInfo`**, **`slas`** for all relevant modes (including pickup when offered), and **`allowMultipleDeliveries`: true** where required. The handler MUST complete within **2.5 seconds**.

**Why this matters**

Incomplete `logisticsInfo` or missing SLAs break checkout shipping selection. Slow responses mark offers unavailable and hurt conversion.

**Detection**

If simulation returns only `items` with prices but omits `logisticsInfo` when the request had `shippingData` → warn. If p95 latency approaches 2s without caching → warn.

**Correct**

```typescript
// Pseudocode: branch on whether checkout context is present
if (hasCheckoutContext(req.body)) {
  return res.json({
    country: req.body.country,
    items: pricedItems,
    logisticsInfo: buildLogisticsPerItem(pricedItems, req.body),
    postalCode: req.body.postalCode,
    allowMultipleDeliveries: true,
  });
}
return res.json({ items: availabilityOnlyItems /* + minimal logistics if required */ });
```

**Wrong**

```typescript
// WRONG: Full checkout body but response omits logisticsInfo / SLAs
res.json({ items: pricedItemsOnly });
```

---

### Constraint: Order placement must return seller `orderId` (reservation)

**`POST /pvt/orders`*

Related in Data & Analytics