Product Variants API
Manage product variants for your products. A variant is a specific version of
a product, for example a size or color, with its own price and inventory.
Endpoints
- List Product Variants -
GET /api/v1/products/{id}/variants/ - Create Product Variant -
POST /api/v1/products/{id}/variants/ - Get Product Variant -
GET /api/v1/products/{id}/variants/{variant_id}/ - Update Product Variant -
PUT /api/v1/products/{id}/variants/{variant_id}/
Digital files have their own endpoints. See
Digital Files.
List Product Variants
Retrieve all variants for a specific product. Variant lists are not paginated,
so has_more is always false.
Endpoint: GET /api/v1/products/{id}/variants/
Permission Required: Read
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
Request
curl -X GET "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/variants/" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"data": [
{
"id": "prv_d0b6fmv28q6vn14peun0",
"name": "Small Red",
"price": 1999,
"sale": null,
"total_inventory": 50,
"fulfillment_type": "physical",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z"
},
{
"id": "prv_xk3mq7r41p8nt26zv9w0",
"name": "Large Blue",
"price": 2499,
"sale": {
"price": 1999
},
"total_inventory": 25,
"fulfillment_type": "physical",
"created_at": "2023-01-01T10:30:00Z",
"updated_at": "2023-01-01T11:00:00Z"
}
],
"has_more": false
}
Error Responses
Product not found
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Failed to get product
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Create Product Variant
Create a new variant for a specific product.
Endpoint: POST /api/v1/products/{id}/variants/
Permission Required: Write
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
Request Body
{
"name": "Medium Green",
"price": 2199,
"inventory": 10
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Variant name |
price |
integer | Yes | Price in the store's smallest currency unit (must be non-negative) |
inventory |
integer | No | Stock count (defaults to 0, must be non-negative) |
Request
curl -X POST "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/variants/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-12345" \
-d '{
"name": "Medium Green",
"price": 2199,
"inventory": 10
}'
Optional Headers:
Idempotency-Key: Unique string to prevent duplicate variant creation (see Idempotency)
Response
Returns the created variant.
Status: 201 Created
{
"id": "prv_j2k5n8p1q4r7t0w3x6z9",
"name": "Medium Green",
"price": 2199,
"sale": null,
"total_inventory": 10,
"fulfillment_type": "physical",
"created_at": "2023-01-01T12:00:00Z",
"updated_at": "2023-01-01T12:00:00Z"
}
Error Responses
Invalid JSON body
Status: 400 Bad Request
{
"error": "Invalid JSON body",
"code": "INVALID_JSON"
}
Missing required field
Status: 400 Bad Request
{
"error": "Variant name is required",
"code": "MISSING_FIELD"
}
Invalid price or inventory
Status: 400 Bad Request
{
"error": "Price must be non-negative",
"code": "INVALID_FIELD"
}
Failed to create variant
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Get Product Variant
Retrieve a single product variant by its ID.
Endpoint: GET /api/v1/products/{id}/variants/{variant_id}/
Permission Required: Read
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
variant_id |
string | Variant public ID (e.g., prv_d0b6fmv28q6vn14peun0) |
Request
curl -X GET "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/variants/prv_d0b6fmv28q6vn14peun0/" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"id": "prv_d0b6fmv28q6vn14peun0",
"name": "Small Red",
"price": 1999,
"sale": null,
"total_inventory": 50,
"fulfillment_type": "physical",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z"
}
Error Responses
Variant not found
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Failed to get variant
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Update Product Variant
Update an existing product variant's price, inventory, or sale.
Endpoint: PUT /api/v1/products/{id}/variants/{variant_id}/
Permission Required: Write
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
variant_id |
string | Variant public ID (e.g., prv_d0b6fmv28q6vn14peun0) |
Request Body
{
"price": 2299,
"inventory": 45,
"sale": {
"price": 1999
}
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
price |
integer | Yes | Price in the store's smallest currency unit (must be non-negative) |
inventory |
integer | Yes | Stock count (must be non-negative) |
sale |
object|null | No | Sale price. Omit or set to null to end the sale |
Omit sale or set it to null to remove an existing sale. Supplying a
sale.price sets or updates the sale.
Request
curl -X PUT "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/variants/prv_d0b6fmv28q6vn14peun0/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-67890" \
-d '{
"price": 2299,
"inventory": 45,
"sale": {
"price": 1999
}
}'
Optional Headers:
Idempotency-Key: Unique string to prevent duplicate variant updates (see Idempotency)
Response
Returns the updated variant.
Status: 200 OK
{
"id": "prv_d0b6fmv28q6vn14peun0",
"name": "Small Red",
"price": 2299,
"sale": {
"price": 1999
},
"total_inventory": 45,
"fulfillment_type": "physical",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T13:30:00Z"
}
Error Responses
Invalid JSON body
Status: 400 Bad Request
{
"error": "Invalid JSON body",
"code": "INVALID_JSON"
}
Invalid price, inventory, or sale price
Status: 400 Bad Request
{
"error": "Price must be non-negative",
"code": "INVALID_FIELD"
}
Variant not found
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Failed to update variant
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Product Variant Object
Fields
| Field | Type | Description |
|---|---|---|
id |
string | Variant public ID |
name |
string | Variant name |
price |
integer | Regular price in the store's smallest currency unit |
sale |
object|null | Sale information if the variant is on sale |
total_inventory |
integer | Current stock count |
fulfillment_type |
string | physical or digital |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |
Sale Object
When a variant is on sale, the sale field contains:
| Field | Type | Description |
|---|---|---|
price |
integer | Sale price in the store's smallest currency unit |
Fulfillment Type
The fulfillment type comes from the product. Physical variants are shipped and
carry inventory. Digital variants are delivered as a download and do not need
stock.