Update Product Draft Variant
Sparse-update a variant on a product's unpublished overlay. Buyers still see the live product.
draft_version is required. The same field allowlist as
Update Product Variant applies.
amount, type, currency, tax_behavior, and recurring_options cannot be changed
after create. Sending any of them returns 422 and nothing is changed — see
Immutable price fields.
Unpublished overlay variants are nested-only — they are not reachable at
Update Product Variant. Sending custom_fields is
ignored — use the nested Custom Fields overlay paths.
Request
PATCH /products/{productId}/draft/variants/{id}
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | Yes | Product UUID |
id | string | Yes | Product variant UUID |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
draft_version | integer | Yes | Current overlay version from Get Product Draft or a prior draft write. Minimum 1. A mismatch returns 409. |
All other fields are optional and match Update Product Variant. Only include the fields you want to change.
Example Request
curl -X PATCH "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/draft/variants/5272bfcf-4e92-458d-b513-80ca474a16e4" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"draft_version": 9,
"name": "100g Sample - roasted"
}'
Attach same-product upsells on the overlay. The target must already be a published
sibling — a variant created only on this overlay and not yet published returns 422.
See Upsells:
curl -X PATCH "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/draft/variants/d91c65aa-b221-4aa4-b626-cf0d8a198749" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"draft_version": 9,
"upsells": [
{
"variant_id": "e903c6d6-163e-4080-a99a-4ee5a1e4f17a",
"text": "Switch to a monthly subscription"
}
]
}'
Response
Success Response (200)
Returns the updated overlay variant plus the new draft_version and a fresh product
preview_url. See Draft preview.
{
"id": "5272bfcf-4e92-458d-b513-80ca474a16e4",
"status": "published",
"type": "one_time",
"recurring_options": null,
"name": "100g Sample - roasted",
"amount": 999,
"currency": "usd",
"checkout_url": null,
"draft_version": 10,
"preview_url": "https://cart.easy.tools/checkout-preview/0632bef5-c308-42cd-9cba-89a7a4f722bb?expires=1749384000&signature=abc123"
}
The response contains the full variant plus draft_version and preview_url. See
Get Product Variant for the complete list of
variant fields; the example above is abbreviated.
Response Fields
Shared variant fields are listed on Get Product Variant. This write adds:
| Field | Type | Nullable | Description |
|---|---|---|---|
draft_version | integer | No | New overlay version after this write. Send it on the next draft write. |
preview_url | string | No | Temporary signed checkout preview of the product. Always reminted. Expires after about one hour. See Draft preview. |
Error Responses
Bad Request (400)
Returned when the product UUID or the variant UUID is malformed.
{
"message": "Invalid product ID"
}
{
"message": "Invalid variant ID"
}
Not Found (404)
Two cases share this status, told apart by the message. The product UUID does not exist, belongs to another store, or points at an archived product:
{
"message": "Product with ID 0632bef5-c308-42cd-9cba-89a7a4f722bb not found"
}
Or the product resolves but the variant is not on its overlay:
{
"message": "Product variant with ID 5272bfcf-4e92-458d-b513-80ca474a16e4 not found"
}
Conflict Error (409 — Stale Draft Version)
Returned when draft_version does not match the current overlay version. GET the draft
and retry with the current draft_version.
{
"message": "The draft was edited elsewhere. GET the draft and retry with the current draft_version."
}
Validation Error (422 Unprocessable Entity)
Returned when draft_version is missing, an immutable price field is sent, or the body
fails the same field rules as
Update Product Variant.
{
"message": "The given data was invalid.",
"errors": {
"draft_version": [
"The draft version field is required."
]
}
}
{
"message": "The amount field cannot be updated. Stripe does not allow changing the amount on a published price.",
"errors": {
"amount": [
"The amount field cannot be updated. Stripe does not allow changing the amount on a published price."
]
}
}