Skip to main content

Create Product Variant

Create a new product variant for a product in your store.

Adding a variant to a product that is currently published requires an active Easytools plan, because the variant goes live immediately. If the store has none, the call returns 422 and no variant is created. Adding a variant to a draft product is always accepted. See Active plan required.

Request

POST /products/{id}/variants

Path Parameters

ParameterTypeRequiredDescription
idstringYesProduct UUID

Request Body

ParameterTypeRequiredDescription
typestringYesVariant type ("one_time" or "recurring")
namestringNoVariant name (max 255 characters)
recurring_optionsobjectNoRecurring options (required if type is "recurring")
recurring_options.intervalstringNoRecurring interval ("day", "week", "month", "year")
recurring_options.interval_countintegerNoNumber of intervals between charges
amountintegerYesPrice in minor units (minimum 0)
trial_period_daysintegerNoTrial period in days (min: 0, recurring variants only)
active_cyclesintegerNoNumber of billing cycles (min: 1, recurring only)
is_hiddenbooleanNoHide variant from checkout (default: false)
quantityintegerNoInventory limit (min: 0, null = unlimited)
has_quantitybooleanNoEnable quantity selector (default: false)
old_priceintegerNoStruck-through compare-at price in major currency units (79 = 79.00 PLN). Min: 0. Unlike amount, which is in minor units (e.g. cents). See Price units.
active_fromstringNoStart selling date (ISO 8601)
active_untilstringNoEnd selling date (ISO 8601, must be >= active_from)
active_daysintegerNoDays of access after purchase (relative-expiry mode, min: 1)
access_untilstringNoFixed access-expiry date (ISO 8601). Also ends the sale window on that date
tax_behaviorstringNoTax handling ("inclusive" or "exclusive")

Example Request

curl -X POST "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/variants" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "one_time",
"name": "250g Package",
"amount": 1999,
"old_price": 29,
"quantity": 100,
"has_quantity": true
}'
curl -X POST "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/variants" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "recurring",
"name": "Monthly Subscription - 250g",
"recurring_options": {
"interval": "month",
"interval_count": 1
},
"amount": 1799,
"trial_period_days": 14,
"active_cycles": 12,
"tax_behavior": "inclusive"
}'

Response

Success Response (201)

Returns the created product variant.

{
"id": "d91c65aa-b221-4aa4-b626-cf0d8a198749",
"type": "one_time",
"recurring_options": null,
"name": "250g Package",
"amount": 1999,
"currency": "usd",
"checkout_url": "https://cart.easy.tools/checkout/premium-coffee?plan=price_123"
}
{
"id": "e903c6d6-163e-4080-a99a-4ee5a1e4f17a",
"type": "recurring",
"recurring_options": {
"interval": "month",
"interval_count": 1
},
"name": "Monthly Subscription - 250g",
"amount": 1799,
"currency": "usd",
"checkout_url": "https://cart.easy.tools/checkout/premium-coffee?plan=price_456"
}

Response Fields

FieldTypeNullableDescription
idstringNoUnique identifier for the product variant (UUID)
typestringNoVariant type ("one_time" or "recurring")
recurring_optionsobjectYesRecurring options (null for one-time variants)
recurring_options.intervalstringNoRecurring interval ("day", "week", "month", "year")
recurring_options.interval_countintegerNoNumber of intervals between charges
namestringYesVariant name
amountintegerNoPrice in minor units
currencystringNoLowercase ISO currency code (inherited from the product)
checkout_urlstringYesDirect checkout URL for this variant. Null until the variant is synced to Stripe.

The response contains the full variant. See Get Product Variant for the complete list of fields; the examples above are abbreviated.

Error Responses

Product Not Found (404)

{
"message": "Product with ID 0632bef5-c308-42cd-9cba-89a7a4f722bb not found"
}

Validation Error (422 Unprocessable Entity)

{
"message": "The given data was invalid.",
"errors": {
"type": [
"The type field is required."
],
"recurring_options": [
"The recurring options field is required when type is recurring."
],
"amount": [
"The amount field is required."
]
}
}

Publishing Not Allowed (422 — No Active Plan)

Returned when the parent product is currently published and the store has no active Easytools plan. No variant is created. Activate a plan and retry — repeating the call as it stands returns the same error. Draft products are unaffected.

This body carries a message and no errors key, so a 422 from this endpoint is distinguished by whether errors is present.

{
"message": "Product cannot be published without an active Easytools plan"
}