Publish Product
Publish a product in your store.
If an unpublished overlay exists (has_draft: true), this call persists that overlay as
the live product — including unpublished draft variants — then drops the overlay and sets
status to published. A product that is already published and still has an overlay is
refreshed the same way. With no overlay, the live product is published (or re-saved if it
is already published).
Your store must have an active Easytools plan. If it does not, the call returns 422 and
the product stays a draft. That also applies when the product is already published.
See Active plan required.
A draft wall_id or footer_id is checked again. If that project is gone, publish
returns 422 and the draft stays. A course connect whose course was deleted is
skipped — if the draft also set that course as the thank-you redirect, the product
is published with no course redirect. Publish applies only the course connects and
disconnects the draft asked for. A draft that did not send player changes no
courses. Only this endpoint applies course changes stored on a draft.
Unpublishing the product, or publishing the draft from the
dashboard, drops them, and the live connected courses stay as they are.
Easytools unavailable on that check, or while connecting or disconnecting a course,
returns 502 and nothing is published — the draft stays. A course connect or
disconnect that completed before the failure already applies to the live product,
and a retry does not send it again, so retrying is safe. An account not connected
to Easytools returns 422. Neither reports the field as invalid. Those fields are
not on this response.
A successful call returns the live product, the same shape as Get Product.
Request
POST /products/{id}/publish
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Product UUID |
Example Request
curl -X POST "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/publish" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
Response
Success Response (200)
Returns the live product (has_draft is false). Same fields as
Get Product.
{
"id": "0632bef5-c308-42cd-9cba-89a7a4f722bb",
"status": "published",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"slug": "premium-coffee-beans",
"image_url": "https://example.com/images/coffee-beans.jpg",
"checkout_url": "https://cart.easy.tools/checkout/0632bef5-c308-42cd-9cba-89a7a4f722bb",
"currency": "usd",
"file": {
"name": "My ebook.pdf",
"url": "https://mysite.com/ebook.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/9c1e7f42-3b8a-4d6e-9f10-2a5c7d3e8b41/download?expires=1749384000&signature=abc123"
},
"files": [
{
"name": "My ebook.pdf",
"url": "https://mysite.com/ebook.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/9c1e7f42-3b8a-4d6e-9f10-2a5c7d3e8b41/download?expires=1749384000&signature=abc123"
},
{
"name": "Bonus chapter.pdf",
"url": "https://mysite.com/bonus-chapter.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/4f7a2d18-6c93-4e5b-8a21-0d9e3f6b7c52/download?expires=1749384000&signature=abc123"
}
],
"active_from": "2026-01-01T00:00:00+00:00",
"active_until": "2026-12-31T23:59:59+00:00",
"show_active_until_counter": true,
"redirect_url": "https://mysite.com/thank-you",
"redirect_time": 5,
"add_redirect_params": true,
"webhook_url": "https://mysite.com/webhook",
"terms_url": "https://mysite.com/terms",
"policy_url": "https://mysite.com/privacy",
"contact_email": "support@mysite.com",
"refund_days": 14,
"delegable": false,
"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": [
{
"id": "d91c65aa-b221-4aa4-b626-cf0d8a198749",
"status": "published",
"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",
"custom_id": "SKU-250G",
"is_hidden": false,
"trial_period_days": null,
"active_cycles": null,
"cancel_early": false,
"keep_access_after_expiring": false,
"allow_multiple_subscriptions": false,
"active_days": 365,
"quantity": 100,
"has_quantity": true,
"old_price": 29,
"active_from": "2026-01-01T00:00:00+00:00",
"active_until": "2026-12-31T23:59:59+00:00",
"access_until": null,
"show_active_until_counter": true,
"tax_behavior": "exclusive",
"refund_days": 14,
"redirect_url": "https://mysite.com/thank-you",
"redirect_time": 5,
"file": {
"name": "Product Guide.pdf",
"url": "https://mysite.com/files/guide.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/b8d4e6a2-51c7-4f39-9e0b-3a7c2d18f5e6/download?expires=1749384000&signature=abc123"
},
"files": [
{
"name": "Product Guide.pdf",
"url": "https://mysite.com/files/guide.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/b8d4e6a2-51c7-4f39-9e0b-3a7c2d18f5e6/download?expires=1749384000&signature=abc123"
},
{
"name": "Quick Start.pdf",
"url": "https://mysite.com/files/quick-start.pdf",
"download_url": "https://cart.easy.tools/api/v1/product-files/2e9b5c71-8d40-4a6f-b312-7f5a9c04d8e3/download?expires=1749384000&signature=abc123"
}
],
"invoice_remarks": "Thank you for your purchase!",
"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,
"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,
"credits": null,
"show_net_price": false,
"pay_what_you_want": null,
"purchase_button_text": null,
"upsells": [],
"custom_fields": null
},
{
"id": "e903c6d6-163e-4080-a99a-4ee5a1e4f17a",
"status": "published",
"type": "recurring",
"recurring_options": {
"interval": "month",
"interval_count": 1
},
"name": "Monthly Subscription - 250g",
"amount": 1799,
"currency": "usd",
"checkout_url": null,
"custom_id": null,
"is_hidden": false,
"trial_period_days": 14,
"active_cycles": 12,
"cancel_early": true,
"keep_access_after_expiring": false,
"allow_multiple_subscriptions": false,
"active_days": null,
"quantity": null,
"has_quantity": false,
"old_price": null,
"active_from": null,
"active_until": null,
"access_until": null,
"show_active_until_counter": null,
"tax_behavior": "exclusive",
"refund_days": null,
"redirect_url": null,
"redirect_time": null,
"file": null,
"files": [],
"invoice_remarks": null,
"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,
"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,
"credits": null,
"show_net_price": false,
"pay_what_you_want": null,
"purchase_button_text": null,
"upsells": [],
"custom_fields": null
}
],
"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.
has_draft is always false — any overlay has been persisted and dropped by this call.
Read slug from the response rather than assuming the one you sent: if that slug was
taken between writing the overlay and this call, the product is stored under a different
one.
Error Responses
Bad Request (400)
{
"message": "Invalid product ID"
}
Not Found Error (404)
Returned when the UUID does not exist, belongs to another store, or points at an archived
product. Only draft and published products can be published.
{
"message": "Product with ID 0632bef5-c308-42cd-9cba-89a7a4f722bb not found"
}
Conflict Error (409 — Stale Draft)
Returned when persisting the overlay would drop unpublished product-field edits, or overwrite live checkout settings, styles, or media that are newer than the overlay. GET the draft again, or discard the draft, then retry.
The body is a flat { "message": "…" } with no error code.
{
"message": "This draft is stale. GET the draft again, or DELETE /products/{id}/draft."
}
Publishing Not Allowed (422 — No Active Plan)
Returned when the store has no active Easytools plan. The product stays a draft, and a product that is already published is refused the same way. Activate a plan and retry — repeating the call as it stands returns the same error.
The body carries a message and no errors key.
{
"message": "Product cannot be published without an active Easytools plan"
}
Validation Error (422 - Project no longer exists)
Returned when a draft Love wall or product legal footer no longer exists. The draft stays. A deleted course is skipped and does not return this error. A thank-you redirect to that course is dropped.
{
"message": "The given data was invalid.",
"errors": {
"wall_id": [
"The selected wall_id is invalid."
]
}
}
Service Unavailable (502)
Returned when Easytools is temporarily unavailable while checking a draft Love wall or legal footer, or while connecting or disconnecting a course. The identifier was not rejected. Nothing is published and the draft stays. A course connect or disconnect that completed before the failure already applies to the live product, and a retry does not send it again, so retrying shortly is safe.
{
"message": "The Easytools service is temporarily unavailable. Please retry."
}
Account Not Connected (422)
Returned when the account is not connected to Easytools, so a project cannot be attached. This is not an invalid wall_id, footer_id, or player.id. The draft stays.
{
"message": "Account is not connected to Easytools"
}