Public Alpha. Easel is in early development, so expect rough edges.

Easel

← API Documentation

Product Options API

Manage product options and their values. Options describe the choices a
customer makes, for example Size or Color. Each option has an ordered list of
values such as Small, Medium, and Large.

Options and values make, rename and merge a product's
variants as the dashboard does. A product can also
start with its options and every combination of their values; see
Options.

Endpoints

Options:

Values:


List Product Options

Retrieve all options for a product, including each option's values. This
endpoint is not paginated.

Endpoint: GET /api/v1/products/{product_id}/options/

Scope Required: products:read

Request

curl -X GET "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "pop_d0b6fmv28q6vn14peun0",
      "name": "Color",
      "type": "color",
      "values": [
        {
          "id": "pov_d0b6fmv28q6vn14peun0",
          "value": "Red",
          "position": 0,
          "hex": "#ff0000"
        },
        {
          "id": "pov_xk3mq7r41p8nt26zv9w0",
          "value": "Blue",
          "position": 1,
          "hex": "#0000ff"
        }
      ],
      "created_at": "2023-01-01T10:00:00Z",
      "updated_at": "2023-01-01T10:15:00Z"
    }
  ]
}

Create Product Option

Create an option for a product. Every variant has one value of each option, so
when the product already has variants, send a default_value: the option is
created with that value, and each variant gets it and is renamed to include
it. A product without variants yet needs no default; add values with
Create Product Option Value.

Endpoint: POST /api/v1/products/{product_id}/options/

Scope Required: products:write

Request Body

{
  "name": "Size",
  "type": "text"
}
Field Type Required Description
name string Yes Option name
type string Yes text or color
default_value string When the product has variants Value given to every existing variant
default_hex string No Hex color of default_value, for color options (e.g. #ff0000)

Request

curl -X POST "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-12345" \
  -d '{"name": "Size", "type": "text"}'

Response

Status: 201 Created

{
  "id": "pop_d0b6fmv28q6vn14peun0",
  "name": "Size",
  "type": "text",
  "values": [],
  "created_at": "2023-01-01T10:00:00Z",
  "updated_at": "2023-01-01T10:00:00Z"
}

Error Responses

Missing required field

Status: 400 Bad Request

{
  "error": "Name is required",
  "code": "MISSING_FIELD"
}

Invalid option type

Status: 400 Bad Request

{
  "error": "Type is required",
  "code": "MISSING_FIELD"
}

Default value missing

The product has variants, but no default_value was sent.

Status: 400 Bad Request

{
  "error": "Invalid 'default_value' parameter: required when the product has variants",
  "code": "INVALID_REQUEST_ERROR"
}

Update Product Option

Rename an option.

Endpoint: PUT /api/v1/products/{product_id}/options/{option_id}/

Scope Required: products:write

Request Body

{
  "name": "Sizing"
}
Field Type Required Description
name string Yes Option name

Request

curl -X PUT "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-67890" \
  -d '{"name": "Sizing"}'

Response

Status: 200 OK

{
  "id": "pop_d0b6fmv28q6vn14peun0",
  "name": "Sizing",
  "type": "text",
  "values": [],
  "created_at": "2023-01-01T10:00:00Z",
  "updated_at": "2023-01-01T10:30:00Z"
}

Delete Product Option

Delete an option and its values, as the dashboard does. Variants that then
have the same values are merged into one, the oldest, and every variant is
renamed without the option's value: deleting Color from "Red, S" and
"Blue, S" leaves one variant, "S". Shoppers' carts lose the product's
variants. Nothing changes once any of the product's variants has been
ordered.

Endpoint: DELETE /api/v1/products/{product_id}/options/{option_id}/

Scope Required: products:write

Request

curl -X DELETE "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 204 No Content

Error Responses

A variant of the product has been ordered

Status: 409 Conflict

{
  "error": "Variants someone has ordered can't be deleted or merged",
  "code": "CONFLICT"
}

Create Product Option Value

Add a value to an option. Values are ordered by position, starting at 0, and
a new one goes last. An option has at most 30 values; adding another fails
with 400 Bad Request and INVALID_FIELD.

Values make variants as they do in the dashboard:

  • An option's first value is given to every variant the product has, and each
    is renamed to include it. It makes no variants.
  • Another value makes one variant for each combination with the other
    options' values, all at once. Adding "L" to Size, beside Color's "Red" and
    "Blue", makes "Red, L" and "Blue, L": values are named in the order the
    options were created, joined by ", ". Each new variant costs what the
    product's first variant does and starts with no stock, SKU or barcode.
  • A value makes no variants while another option has no values yet, or while
    the product has no variants at all (one made through the API without
    options): there is no first variant to price them like.

A value whose combinations would take the product past 100 variants is
refused with 409 Conflict and TOO_MANY_VARIANTS, and neither the value nor
any variant is made.

Endpoint: POST /api/v1/products/{product_id}/options/{option_id}/values/

Scope Required: products:write

Request Body

{
  "value": "L",
  "hex": null
}
Field Type Required Description
value string Yes Value text
hex string No Hex color for color options (e.g. #ff0000)

Request

curl -X POST "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/values/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-13579" \
  -d '{"value": "L"}'

Response

Status: 201 Created

The new value and the variants it made, in the order made. variants is
always present, and empty when the value made none.

{
  "value": {
    "id": "pov_d0b6fmv28q6vn14peun0",
    "value": "L",
    "position": 2
  },
  "variants": [
    {
      "id": "prv_d0b6fmv28q6vn14peun0",
      "name": "Red, L",
      "price": 2500,
      "sale": null,
      "total_inventory": 0,
      "delivery": "physical",
      "created_at": "2023-01-01T10:00:00Z",
      "updated_at": "2023-01-01T10:00:00Z",
      "external_source": null,
      "external_id": null,
      "weight_grams": null,
      "sku": null,
      "barcode": null
    },
    {
      "id": "prv_xk3mq7r41p8nt26zv9w0",
      "name": "Blue, L",
      "price": 2500,
      "sale": null,
      "total_inventory": 0,
      "delivery": "physical",
      "created_at": "2023-01-01T10:00:00Z",
      "updated_at": "2023-01-01T10:00:00Z",
      "external_source": null,
      "external_id": null,
      "weight_grams": null,
      "sku": null,
      "barcode": null
    }
  ]
}

Each variant is a Product Variant Object.

Error Responses

Missing value

Status: 400 Bad Request

{
  "error": "Value is required",
  "code": "MISSING_FIELD"
}

The variants would pass the cap

Status: 409 Conflict

{
  "error": "A product can have at most 100 variants",
  "code": "TOO_MANY_VARIANTS"
}

Update Product Option Value

Update a value's text and color. Every variant using the value is renamed to
match.

Endpoint: PUT /api/v1/products/{product_id}/options/{option_id}/values/{value_id}/

Scope Required: products:write

Request Body

{
  "value": "Extra Small",
  "hex": null
}

Request

curl -X PUT "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/values/pov_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-24680" \
  -d '{"value": "Extra Small"}'

Response

Status: 200 OK

{
  "id": "pov_d0b6fmv28q6vn14peun0",
  "value": "Extra Small",
  "position": 0
}

Move Product Option Value Up

Move a value one position earlier in the option's list.

Endpoint: POST /api/v1/products/{product_id}/options/{option_id}/values/{value_id}/move-up/

Scope Required: products:write

Request

curl -X POST "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/values/pov_d0b6fmv28q6vn14peun0/move-up/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Idempotency-Key: unique-request-id-11223"

Response

Status: 204 No Content

There is no move-down endpoint. To reorder downward, move the other values up.


Delete Product Option Value

Delete a value from an option, as the dashboard does. Every variant has a
value of each option, so when variants use the value and the option has
others, name one to take its place with replacement_id. The variants are
given it and renamed, and any that then match another variant's values are
merged into the oldest: deleting "Red" in favor of "Blue" turns "Red, S" into
"Blue, S", merged with the existing "Blue, S". Shoppers' carts lose the
variants that used the deleted value. Nothing changes once any of the
variants involved has been ordered.

A value no variant uses, or an option's only value, needs no replacement;
deleting an option's only value takes it off its variants.

Endpoint: DELETE /api/v1/products/{product_id}/options/{option_id}/values/{value_id}/

Scope Required: products:write

Query Parameters

Parameter Type Required Description
replacement_id string When variants use the value and the option has other values Another value of the same option, given to the variants in its place

Request

curl -X DELETE "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/options/pop_d0b6fmv28q6vn14peun0/values/pov_d0b6fmv28q6vn14peun0/?replacement_id=pov_xk3mq7r41p8nt26zv9w0" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 204 No Content

Error Responses

Replacement missing

Status: 400 Bad Request

{
  "error": "Invalid 'replacement_id' parameter: required when variants use the value and the option has others",
  "code": "INVALID_REQUEST_ERROR"
}

Replacement is the value deleted

Status: 400 Bad Request

{
  "error": "Invalid input",
  "code": "INVALID_FIELD"
}

A variant involved has been ordered

Status: 409 Conflict

{
  "error": "Variants someone has ordered can't be deleted or merged",
  "code": "CONFLICT"
}

Value or replacement not found

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

Product Option Object

Fields

Field Type Description
id string Option public ID
name string Option name
type string text or color
values array Option values
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp

Product Option Value Object

Fields

Field Type Description
id string Value public ID
value string Value text
position integer Sort position, starting at 0
hex string|null Hex color for color options