# Cart Lifecycle Through MCP

> Create, edit, preview, publish and restore cart profiles with version checks and promotion readiness.

Canonical URL: https://3bdc8bdc6dfd:3005/guides/cart-lifecycle

The MCP supports the same cart lifecycle as the app. Design and promotion
changes save a draft. Publishing changes the live profile and synchronizes
managed Shopify discounts, so it requires explicit approval of the exact draft
version.

Call `lexsis_discover` with the router and action below for its current schema.
Put the action parameters inside `args` when calling a consolidated tool.

Cart write responses default to compact summaries with `cart_profile_id` and
`version`; use `response: "full"` for complete profile data. `lexsis_cart.get`
supports `fields` for selective reads. See [Preview and Verify Cart Edits](/guides/cart-edit-loop)
for dry runs and sample-cart URLs.

## Actions and approval

| Router | Action | Effect |
|---|---|---|
| `lexsis_drafts` | `cart_create` | New unpublished profile |
| `lexsis_drafts` | `cart_duplicate` | Copy the current draft into a new profile |
| `lexsis_drafts` | `cart_edit` | Versioned design and composition edit |
| `lexsis_drafts` | `cart_promotions_edit` | Versioned promotion edit and readiness preview |
| `lexsis_cart` | `preview` | Preview a saved draft without publication |
| `lexsis_cart` | `preview_states` | Six sample-cart URLs, snapshots and static checks |
| `lexsis_live_ops` | `cart_publish` | Publish the approved version and synchronize Shopify |
| `lexsis_live_ops` | `cart_rollback` | Restore a historical version into a new forward draft |
| `lexsis_live_ops` | `cart_set_default` | Change live store-default resolution |
| `lexsis_drafts` | `cart_assign_campaign` | Assign a published profile, or clear the campaign override |
| `lexsis_drafts` | `cart_archive` | Archive an unused profile; optionally reassign its references |
| `lexsis_cart` | `get` | Read the draft, effective profile and optional audit history |

Publishing, default changes, campaign/page assignment and archive with
reassignment require publish access and explicit approval. Campaign assignment
lives under `lexsis_drafts` for compatibility, but **changes live resolution**.
Archiving a default or assigned profile without a replacement fails.
Rollback is draft-only; separately approve and publish the restored draft.

## Create and edit

Use `lexsis_drafts.cart_create`:

```json
{
  "store_id": "STORE_UUID",
  "name": "Campaign cart",
  "from_preset": "default"
}
```

Presets are `default`, `subscription`, and `aov_booster`. Alternatively provide
`from_profile_id` to copy a profile in that store. The two source options are
mutually exclusive. Store currency comes from the connected store.

To duplicate directly, call `lexsis_drafts.cart_duplicate` with
`cart_profile_id` and `name`. Neither creation path publishes or creates
discounts.

Apply design with `lexsis_drafts.cart_edit`, using the returned profile version:

```json
{
  "cart_profile_id": "PROFILE_UUID",
  "expected_version": 1,
  "patch": {
    "design_patch": {"shell": {"title": "Your cart"}}
  }
}
```

## Edit promotions

Call `lexsis_drafts.cart_promotions_edit` with the latest version:

```json
{
  "cart_profile_id": "PROFILE_UUID",
  "expected_version": 2,
  "patch": {
    "rewards": [{
      "id": "shipping",
      "type": "free_shipping",
      "title": "Free shipping",
      "threshold": 150000,
      "discount_source": "managed",
      "enabled": true
    }],
    "coupon_settings": {
      "enabled": true,
      "allow_manual_entry": false,
      "coupons": []
    },
    "payment_settings": {
      "enabled": true,
      "placement": "below_checkout",
      "providers": ["visa", "mastercard"]
    }
  }
}
```

`threshold` and fixed monetary values use minor currency units: `150000` means
₹1,500 for an INR store. Use the actual store currency and verified catalog
IDs. Managed reward codes follow the saved reward contract; existing Shopify
codes are verified rather than overwritten.

| Patch field | Patch semantics |
|---|---|
| `rewards` | Merge rows by `id`; supports reward type, threshold, title, enabled state, gift products/variants and qualifying products/collection |
| `offer_slots` | Merge rows by `id`, including placement, product source and enabled state |
| `quantity_promotions` | Merge rows by `id`; managed or merchant automatic promotions |
| `cart_rules` | Merge rules by `id`; conditions and actions use the existing cart-rule contract |
| `coupon_settings` | Merge settings; `coupons` replaces the allow-list |
| `payment_settings` | Merge settings; `providers` replaces the ordered provider list |

Omitted rows remain unchanged. An empty row-patch array is a no-op. Remove a
row explicitly:

```json
{"rewards": [{"id": "shipping", "operation": "remove"}]}
```

Payment placement accepts `inside_checkout`, `below_checkout`, or `hidden`.
Design controls remain available through `cart_edit`. An explicit promotion
placement/provider edit also updates an existing design override for that field.

The response includes `profile` and `readiness`. Malformed input or stale
versions fail before saving. Incomplete promotion setup can remain a draft;
the readiness preview explains what must be fixed. If Shopify readiness cannot
be checked, the saved draft returns `ready:false` with `readiness_unavailable`.
No Shopify discount writes occur during this edit.

## Preview and publish

Call `lexsis_cart.preview` with `cart_profile_id` and optionally `page_id`.
Verify the returned version, mobile and desktop layout, empty/populated states,
and relevant promotion states. A preview does not prove Shopify discounts have
been provisioned.

After the user explicitly approves the exact version, call
`lexsis_live_ops.cart_publish`:

```json
{
  "cart_profile_id": "PROFILE_UUID",
  "expected_version": 3,
  "allow_partial": false,
  "skip_reward_ids": []
}
```

The response includes `published_version`, `shopify.discounts_created`,
`shopify.discounts_updated`, `shopify.discounts_disabled`, and `warnings`.
Resolving Shopify contracts can create an additional version; use the returned
version rather than assuming it equals the input.

- `VERSION_CONFLICT`: re-read the draft and obtain approval for its current version.
- `CART_NOT_READY`: inspect `issues`, fix the draft and preview again.
- `allow_partial:true` only permits the explicitly listed `skip_reward_ids` to
  publish disabled. Remaining reward or non-reward issues still block publication.
- Discounts shared by another published profile remain active and return a warning.

The previous published profile stays live until Shopify work succeeds and the
database transaction commits. Failed writes trigger cleanup of new discounts
and restoration of retired discounts. Shopify does not support a transaction
across multiple mutations: if cleanup cannot be confirmed, the tool returns
`CART_PUBLISH_RECOVERY_REQUIRED` with recovery details. Resolve that condition
before retrying; do not treat it as a successful publish.

## Restore, assign and archive

Restore a previous configuration with `lexsis_live_ops.cart_rollback`:

```json
{"cart_profile_id": "PROFILE_UUID", "target_version": 1}
```

This creates a new draft version and keeps the existing live pointer unchanged.
Review it, then separately approve `cart_publish`. Managed discounts retired
by a later version are verified and reactivated during publication when needed.

Set the default with `lexsis_live_ops.cart_set_default`:

```json
{"store_id": "STORE_UUID", "cart_profile_id": "PUBLISHED_PROFILE_UUID"}
```

Assign a campaign with `lexsis_drafts.cart_assign_campaign`:

```json
{"campaign_id": "CAMPAIGN_UUID", "cart_profile_id": "PUBLISHED_PROFILE_UUID"}
```

Pass `cart_profile_id:null` to restore fallback resolution. All targets must
belong to the same authorized store.

Archive with `lexsis_drafts.cart_archive`:

```json
{"cart_profile_id": "OLD_PROFILE_UUID", "reassign_to": "PUBLISHED_REPLACEMENT_UUID"}
```

Omit `reassign_to` only when the profile is neither default nor assigned.
Reassignment preserves page/campaign assignments and their priority/enabled
settings. Archival does not delete historical snapshots or mutate Shopify.

## Audit history

Call `lexsis_cart.get` with `cart_profile_id` and `include_history:true`.
It returns the latest 100 lifecycle events, including actor kind/user ID,
authenticated MCP client, timestamp, version and a diff summary. Custom source
and credentials are excluded from summaries. Existing snapshots remain
available in the app's version history.

Capabilities advertise `lifecycle_access:"mcp_with_approval"` and
`promotion_access:"draft_then_publish"`. The custom-module script contract is
listed separately under `module_lifecycle`. These actions require the updated
API and MCP releases; documentation availability is not deployment proof.
