Skip to main content

Create Product

Create a new product in your store.

status is optional — omit it to create as draft. Creating a product with status: published requires an active Easytools plan. If the store has none, the call returns 422 and no product is created. status: draft is always accepted. See Active plan required.

Checkout appearance is not on this body. After create, set styles, settings, and gallery with the nested endpoints — see Checkout appearance. Sending styles, settings, or media here is ignored. The response leaves those keys null.

Checkout and waitlist field definitions are also nested — see Custom Fields. Sending custom_fields or waitlist_custom_fields here is ignored. The response leaves those keys null. Checkout order bumps are nested — see Order Bumps. Sending order_bumps here is ignored. After-purchase cross-sells are nested — see Cross-sells. Sending cross_sells here is ignored.

Request​

POST /products

Request Body​

ParameterTypeRequiredDescription
statusstringNoProduct status (draft or published). Omit to create as draft.
namestringYesProduct name (max 255 characters)
descriptionstringNoProduct description (max 10,000 characters)
image_urlstringNoURL to the product image (max 2048 characters). The image is downloaded and stored — see Product images.
currencystringYesISO currency code (3 characters, e.g., "usd", "eur")
slugstringNoCustom URL slug. Must match pattern ^[a-z0-9-]+$ and be unique per store.
active_fromstringNoStart selling date (ISO 8601 format)
active_untilstringNoStop selling date (ISO 8601 format). Must be after or equal to active_from.
show_active_until_counterbooleanNoShow countdown timer on checkout page. Defaults to false.
redirect_urlstringNoPost-purchase redirect URL (max 1000 characters)
redirect_timeintegerNoRedirect delay in seconds. Defaults to null.
add_redirect_paramsbooleanNoInclude order parameters in redirect URL. Defaults to true.
webhook_urlstringNoWebhook URL for order events (max 255 characters)
terms_urlstringNoTerms & conditions URL (max 255 characters)
policy_urlstringNoPrivacy policy URL (max 255 characters)
contact_emailstringNoProduct contact email (max 255 characters)
refund_daysintegerNoRefund period in days. Set to 0 to disable refunds.
show_discount_fieldbooleanNoShow promo code field on checkout page
delegablebooleanNoAllow order delegation/gifting
hide_tax_id_fieldbooleanNoHide tax ID field on checkout page. Defaults to false.
require_tax_idbooleanNoRequire tax ID on checkout page. Defaults to false.
photo_zoomablebooleanNoEnable image zoom on checkout page. Defaults to false.
show_confettibooleanNoShow confetti animation after purchase. Defaults to false.
generate_qr_codebooleanNoGenerate QR code for product. Defaults to false.
show_delegationbooleanNoShow the access-delegation control on checkout. Defaults to false.
delegation_labelstringNoLabel for the access-delegation control (max 250 characters).
delegable_if_multiplebooleanNoAllow delegation only when buying more than one. Defaults to false.
has_shippingbooleanNoCollect a delivery address at checkout. Defaults to false. Distinct from delivery_enabled.
delivery_enabledbooleanNoEnable parcel delivery. Defaults to false. When true, delivery_service and a complete delivery_options object are required.
delivery_servicestringNoCarrier slug. See Checkout form. Required when delivery_enabled is true.
delivery_address_optionalbooleanNoWhether the delivery address is optional. Defaults to true.
delivery_optionsobjectNoParcel package. See Delivery Options Object. Required in full when delivery_enabled is true.
shipping_phone_requiredbooleanNoRequire a phone number with the delivery address. Defaults to false.
phone_tooltipstringNoHelper text for the shipping phone field (max 250 characters).
mandatory_consentstringNoLabel for the mandatory checkout consent (max 500 characters). Omit or null turns it off.
optional_consentstringNoLabel for the optional checkout consent (max 500 characters).
digital_consentstringNoLabel for the digital-content consent (max 500 characters).
newsletter_consentstringNoLabel for the newsletter opt-in (max 500 characters).
newsletter_consent_requiredbooleanNoWhether the newsletter opt-in is required. Defaults to false.
newsletter_discountobjectNoDiscount offered with newsletter opt-in. See Newsletter Discount Object. Do not send currency.
invoice_remarksstringNoRemarks printed on invoices (max 250 characters).
vat_ratestringNoVAT rate as a string (23, zw, np). Not a number. See Invoice, tax, portal, waitlist, and QR.
gtu_codeintegerNoGTU code 1–13 as stored, not a GTU_01 label.
flat_ratenumberNoFlat-rate tax percent: 17, 15, 14, 12.5, 12, 10, 8.5, 5.5, 3, or 2.
exempt_tax_kindstringNoExemption basis when VAT is zw (max 255 characters). Not required when vat_rate is zw.
tax_categorystringNoTax category: saas, ebook, course, webinar, digital, consulting, physical, or exempt. Distinct from variant tax_behavior.
dashboard_headerstringNoSelf-service portal header (max 250 characters).
long_descriptionstringNoSelf-service portal body (max 25,000 characters). Distinct from description.
cta_textstringNoSelf-service portal call-to-action label (max 50 characters).
cta_urlstringNoSelf-service portal call-to-action URL (max 255 characters).
contact_phonestringNoProduct contact phone (max 50 characters).
contact_website_urlstringNoProduct contact website (max 255 characters). Distinct from the store website_url.
contact_additional_infostringNoExtra product contact copy (max 5,000 characters).
footer_textstringNoCheckout footer copy (max 500 characters). Omit persists as "", not JSON null.
waitlist_enabledbooleanNoWhether the waitlist is enabled. Defaults to false.
waitlist_require_first_namebooleanNoWhether the waitlist requires a first name. Defaults to false.
waitlist_require_last_namebooleanNoWhether the waitlist requires a last name. Defaults to false.
qr_code_infostringNoExtra text shown with the QR code (max 250 characters).
creditsintegerNoQR credits. Omit or null means credits are off, not zero. Minimum 0, maximum 4294967295 (422 if exceeded).
reset_creditsbooleanNoWhether credits reset after use. Defaults to false.
fileobjectNoSingle downloadable file. Legacy shortcut equivalent to files: [file]. See File Object.
filesarrayNoUp to 5 downloadable files. Each entry is a File Object. When provided, this supersedes file.

Every URL in the body must start with http:// or https:// and include a host. See URL fields for what is accepted and what returns 422.

File Object​

ParameterTypeRequiredDescription
namestringYesDisplay name shown in the customer portal (max 100 characters)
urlstringYesThe file's location (max 2048 characters): a URL to attach the file by link, or the url of a file read back from the API

Reads add a read-only third property, download_url — see File Object. Requests take name and url only.

note

A product can have up to 5 downloadable files. Use files (array) to attach more than one. The singular file field is a backward-compatible shortcut for a single file; if both are sent, files wins.

Example Request​

Basic product creation — status omitted, so the product is created as draft:

curl -X POST "https://cart.easy.tools/api/v1/products" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"image_url": "https://example.com/images/coffee-beans.jpg",
"currency": "usd",
"file": {
"name": "My ebook.pdf",
"url": "https://mysite.com/ebook.pdf"
}
}'

Product with multiple downloadable files:

curl -X POST "https://cart.easy.tools/api/v1/products" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "published",
"name": "Premium Coffee Bundle",
"currency": "usd",
"files": [
{ "name": "My ebook.pdf", "url": "https://mysite.com/ebook.pdf" },
{ "name": "Bonus chapter.pdf", "url": "https://mysite.com/bonus-chapter.pdf" }
]
}'

Product with advanced options:

curl -X POST "https://cart.easy.tools/api/v1/products" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "published",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"image_url": "https://example.com/images/coffee-beans.jpg",
"currency": "usd",
"slug": "premium-arabica-coffee",
"active_from": "2026-02-01T00:00:00Z",
"active_until": "2026-03-01T00:00:00Z",
"show_active_until_counter": true,
"redirect_url": "https://mysite.com/thank-you",
"redirect_time": 5,
"add_redirect_params": true,
"terms_url": "https://mysite.com/terms",
"contact_email": "support@mysite.com",
"refund_days": 14,
"show_discount_field": true,
"delegable": true,
"hide_tax_id_field": false,
"require_tax_id": false,
"photo_zoomable": true,
"show_confetti": true,
"generate_qr_code": false
}'

Product with delivery address collection and a newsletter discount:

curl -X POST "https://cart.easy.tools/api/v1/products" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Coffee Beans",
"currency": "usd",
"has_shipping": true,
"shipping_phone_required": true,
"mandatory_consent": "I agree to the terms of sale",
"newsletter_consent": "Send me roasting notes and offers",
"newsletter_discount": {
"amount": 500,
"duration": "once"
}
}'

Product with VAT, waitlist names, and QR credits:

curl -X POST "https://cart.easy.tools/api/v1/products" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Coffee Beans",
"currency": "usd",
"vat_rate": "23",
"tax_category": "digital",
"waitlist_enabled": true,
"waitlist_require_first_name": true,
"credits": 10
}'

Response​

Success Response (201)​

Returns the created product with its empty variants array and all fields. The example matches the advanced request (status: published). A body with only name and currency returns status: draft and the checkout-flag defaults from the table above.

{
"id": "0632bef5-c308-42cd-9cba-89a7a4f722bb",
"status": "published",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"slug": "premium-arabica-coffee",
"image_url": "https://example.com/images/coffee-beans.jpg",
"checkout_url": "https://cart.easy.tools/checkout/0632bef5-c308-42cd-9cba-89a7a4f722bb",
"currency": "usd",
"file": null,
"files": [],
"active_from": "2026-02-01T00:00:00+00:00",
"active_until": "2026-03-01T00:00:00+00:00",
"show_active_until_counter": true,
"redirect_url": "https://mysite.com/thank-you",
"redirect_time": 5,
"add_redirect_params": true,
"webhook_url": null,
"terms_url": "https://mysite.com/terms",
"policy_url": null,
"contact_email": "support@mysite.com",
"refund_days": 14,
"delegable": true,
"show_discount_field": true,
"hide_tax_id_field": false,
"require_tax_id": false,
"photo_zoomable": true,
"show_confetti": true,
"generate_qr_code": false,
"show_delegation": false,
"delegation_label": null,
"delegable_if_multiple": false,
"has_shipping": false,
"delivery_enabled": false,
"delivery_service": null,
"delivery_address_optional": true,
"delivery_options": null,
"shipping_phone_required": false,
"phone_tooltip": null,
"mandatory_consent": null,
"optional_consent": null,
"digital_consent": null,
"newsletter_consent": null,
"newsletter_consent_required": false,
"newsletter_discount": null,
"invoice_remarks": null,
"vat_rate": null,
"gtu_code": null,
"flat_rate": null,
"exempt_tax_kind": null,
"tax_category": null,
"dashboard_header": null,
"long_description": null,
"cta_text": null,
"cta_url": null,
"contact_phone": null,
"contact_website_url": null,
"contact_additional_info": null,
"footer_text": "",
"waitlist_enabled": false,
"waitlist_require_first_name": false,
"waitlist_require_last_name": false,
"qr_code_info": null,
"credits": null,
"reset_credits": false,
"variants": [],
"custom_fields": null,
"waitlist_custom_fields": null,
"styles": null,
"settings": null,
"media": null,
"has_draft": false
}

Response Fields​

See Get Product for a complete list of response fields.

Error Responses​

Validation Error (422 Unprocessable Entity)​

{
"message": "The given data was invalid.",
"errors": {
"name": [
"This field is required."
],
"status": [
"The status field must be one of: draft, published."
],
"currency": [
"The currency field must be exactly 3 characters."
]
}
}

Slug validation errors:

{
"message": "The given data was invalid.",
"errors": {
"slug": [
"The slug 'existing-slug' is already in use by another product."
]
}
}
{
"message": "The given data was invalid.",
"errors": {
"slug": [
"The slug field format is invalid."
],
"active_until": [
"The active until field must be a date after or equal to active from."
]
}
}

Sellability fields use the same 422 envelope. See Checkout form for the full matrix. Invoice, tax, portal, waitlist, and QR fields use it too — see Invoice, tax, portal, waitlist, and QR. Sending delivery_enabled without a carrier:

{
"message": "The given data was invalid.",
"errors": {
"delivery_service": [
"The delivery service field is required when delivery enabled is true."
]
}
}

Publishing Not Allowed (422 — No Active Plan)​

Returned when status is published and the store has no active Easytools plan. No product is created. Send status: draft instead, or activate a plan and retry.

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"
}