Skip to main content

Create Custom Field

Append a custom field to a collection, then reindex order to 0..n-1. An internal UUID is minted and never returned. Duplicate name in the same collection returns 422.

Live writes return 409 when the product has has_draft: true — see Live writes while a draft exists. Draft writes require draft_version and return it plus preview_url.

order in the body is optional; the server always appends, then reindexes.

Request

Live:

  • POST /products/{productId}/custom-fields
  • POST /products/{productId}/waitlist-custom-fields
  • POST /product-variants/{id}/custom-fields

Draft:

  • POST /products/{productId}/draft/custom-fields
  • POST /products/{productId}/draft/waitlist-custom-fields
  • POST /products/{productId}/draft/variants/{id}/custom-fields

Path Parameters

ParameterTypeRequiredDescription
productIdstringYesProduct UUID (product-nested paths).
idstringYesVariant UUID (variant-nested paths).

Request Body

ParameterTypeRequiredDescription
namestringYesIdentity slug. Pattern ^[a-z0-9_-]+$, max 50.
typestringYesSee Types.
labelstringYesBuyer-facing copy, max 255.
placeholderstringNoForm-hint copy, max 255.
enabledbooleanNoDefaults to true.
requiredbooleanNoDefaults to false.
orderintegerNoOptional; the server stamps append then reindexes 0..n-1.
validationobjectNo{ min, max } or null. Extra precision returns 422.
optionsarrayWhen type is selectAt least one { value, label }.
sync_easymailbooleanNoDefaults to false.
draft_versionintegerDraft onlyCurrent overlay version. Minimum 1. A mismatch returns 409.

Example Request

curl -X POST "https://cart.easy.tools/api/v1/products/0632bef5-c308-42cd-9cba-89a7a4f722bb/custom-fields" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "size",
"type": "select",
"label": "Size",
"required": true,
"options": [
{ "value": "s", "label": "S" },
{ "value": "m", "label": "M" }
]
}'

Draft create adds "draft_version": 8 to the body and uses the /draft/custom-fields path.

Response

Success Response (201)

Live returns the Custom Field Object. Draft returns that object plus draft_version and preview_url.

{
"name": "size",
"type": "select",
"label": "Size",
"placeholder": null,
"enabled": true,
"required": true,
"order": 0,
"validation": null,
"options": [
{ "value": "s", "label": "S" },
{ "value": "m", "label": "M" }
],
"sync_easymail": false
}

Error Responses

Bad Request (400)

{
"message": "Invalid product ID"
}

Not Found Error (404)

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

Conflict Error (409 — Unpublished Draft)

Live write while has_draft is true:

{
"message": "This product has an unpublished draft. Publish, unpublish, or delete the draft before making live changes."
}

Conflict Error (409 — Stale Draft Version)

Draft write when draft_version does not match:

{
"message": "The draft was edited elsewhere. GET the draft and retry with the current draft_version."
}

Validation Error (422 Unprocessable Entity)

{
"message": "The given data was invalid.",
"errors": {
"name": ["The name has already been taken."]
}
}

type=select without options, a name that fails the slug pattern, or validation.precision also return 422.

Unauthorized Error (401)

{
"message": "Unauthenticated."
}

Forbidden Error (403)

{
"message": "This action is unauthorized."
}