> ## Documentation Index
> Fetch the complete documentation index at: https://docs.droplinked.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cart Composition for Agents

> Build a multi-line Droplinked cart across turns using `start_checkout` plus the four cart-mutation tools (cart.addLine, cart.updateLineQuantity, cart.removeLine, cart.applyDiscount).

`start_checkout` was the original "find ⇨ buy" path: an agent calls it once with a SKU,
gets back a hosted Droplinked checkout URL, and hands the buyer off to pay. That works for
single-SKU intent ("buy this thing") but not for **multi-turn agentic composition**, where
the agent (or buyer) wants to *try* a cart configuration before paying.

The four **cart-mutation tools** close that loop:

| Tool                      | What it does                                     |
| ------------------------- | ------------------------------------------------ |
| `cart.addLine`            | Add another SKU to an existing cart              |
| `cart.updateLineQuantity` | Change the quantity of a SKU already in the cart |
| `cart.removeLine`         | Remove a SKU from the cart                       |
| `cart.applyDiscount`      | Apply a merchant-issued discount / coupon code   |

All four expect the **encrypted `cartId`** returned by `start_checkout` — pass it back
verbatim; it's already obfuscated by the backend's `DecryptCartIdPipe`.

***

## Canonical multi-line composition flow

```text theme={null}
1. search_products({ query: "blue sneaker size 10" })       → [skuA, skuB, …]
2. start_checkout({ shopId, skuId: skuA, quantity: 1, … })  → { cartId, checkoutUrl }
3. cart.addLine({ cartId, skuId: skuB, quantity: 2 })        → updated cart
4. cart.updateLineQuantity({ cartId, skuId: skuA, quantity: 3 })
                                                              → bumped cart total
5. cart.applyDiscount({ cartId, discountCode: "WELCOME10" }) → discount applied
6. Buyer (or agent) navigates to `checkoutUrl` and pays
```

Each step returns the updated `cart` envelope so the agent can show the running subtotal,
line list, and discount before commit. There is no separate "preview" call — every mutation
is the preview.

***

## Tool reference

### `cart.addLine`

```json theme={null}
{
  "cartId": "ENC:...",
  "skuId":  "65ab12cd34ef567890123456",
  "quantity": 2
}
```

Idempotent on (`cartId`, `skuId`): calling twice with the same SKU bumps the quantity on
the existing line rather than creating a duplicate.

**Backs**: `POST /v2/carts/:cartId/products`

### `cart.updateLineQuantity`

```json theme={null}
{
  "cartId":   "ENC:...",
  "skuId":    "65ab12cd34ef567890123456",
  "quantity": 5
}
```

Sets the line to the specified quantity. **Passing `quantity: 0` removes the line** — same
effect as calling `cart.removeLine` but in a single call, which is convenient when the
agent is decrementing.

**Backs**: `PATCH /v2/carts/:cartId/products/:skuId`

### `cart.removeLine`

```json theme={null}
{
  "cartId": "ENC:...",
  "skuId":  "65ab12cd34ef567890123456"
}
```

Removes the line entirely. The returned cart shows the updated lines + total. Removing the
last line leaves the cart empty but still usable — the buyer can continue browsing and the
agent can add new lines.

**Backs**: `DELETE /v2/carts/:cartId/products/:skuId`

### `cart.applyDiscount`

```json theme={null}
{
  "cartId":       "ENC:...",
  "discountCode": "SAVE20"
}
```

Validates the discount code at the merchant level, computes the discount, and returns the
updated cart with the discount amount + label resolved. The code is case-insensitive on
the backend but is preserved on the MCP surface so agents can run idempotency checks
against the exact value they sent.

An invalid or expired code surfaces as a structured error envelope.

**Backs**: `POST /v2/carts/:cartId/coupon`

***

## Error envelope

All four tools follow the same envelope shape so agents can branch on JSON instead of
catching exceptions:

```json theme={null}
// Happy path
{ "status": "ok", "cartId": "ENC:...", "...": "..." }

// Failure (backend error, validation error, network error)
{ "status": "error", "reason": "<reason_enum>", "message": "…human-readable…" }
```

The structured `reason` enum lets agents branch programmatically (e.g.
`reason: "INVALID_COUPON"` vs `reason: "BACKEND_5XX"`).

***

## When NOT to use the cart-mutation tools

* **Agent only knows the buyer wants one SKU**: use `start_checkout` alone. The mutation
  tools are pure overhead for single-SKU intent.
* **Agent is composing for an *unauthenticated* buyer**: there is no "guest cart" — the
  cart belongs to the email passed to `start_checkout`. Mutations apply to that cart.
* **Agent wants to express discount programmatically**: the only discount surface is the
  discount code. There is no `cart.applyPercentageOff` or similar — merchants own their
  promo logic via discount codes.

***

## Related

* [Inventory MCP](/agentic/inventory-mcp) — full tool inventory
* [MCP Server](/agentic/mcp-server) — installation and environment reference
* [Storefront MCP discovery](/agentic/storefront-mcp-discovery) — the `search_products`
  / `get_product` family that precedes `start_checkout`
* [ACP feed](/agentic/acp-feed) — the bulk-discovery feed agents can crawl before
  cart-composing
