Products API
Manage products in your store. A product has a name, a status, an optional
description, and one or more variants that hold the price and inventory.
Related resources:
- Product Variants for price and stock
- Product Options for size, color, and similar choices
- Product Images for photos
- Tags and product tags for organization
- Digital Files for downloadable products
Endpoints
- List Products -
GET /api/v1/products/ - Create Product -
POST /api/v1/products/ - Get Product -
GET /api/v1/products/{id}/ - Update Product -
PUT /api/v1/products/{id}/ - Duplicate Product -
POST /api/v1/products/{id}/duplicate/
List Products
Retrieve a paginated list of products for your store.
Endpoint: GET /api/v1/products/
Permission Required: Read
Query Parameters
| Parameter | Type | Description |
|---|---|---|
after |
string | Return products after this public ID |
before |
string | Return products before this public ID |
limit |
integer | Number of products to return (default 10, max 100) |
search |
string | Search products by name or description |
status |
string | Filter by product status (draft, active, archived) |
after and before cannot be used together.
Request
curl -X GET "https://studio.easel.engineering/api/v1/products/?status=active&limit=20" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"data": [
{
"id": "pro_d0b6fmv28q6vn14peun0",
"name": "Premium T-Shirt",
"status": "active",
"description": "High-quality cotton t-shirt",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z"
}
],
"has_more": true
}
Error Responses
Invalid query parameter
Status: 400 Bad Request
{
"error": "Invalid 'after' parameter",
"code": "INVALID_FIELD"
}
Failed to list products
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Create Product
Create a new product in your store. New products are created with the draft
status, physical fulfillment, and no variants.
Endpoint: POST /api/v1/products/
Permission Required: Write
Request Body
{
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Product name |
description |
string | No | Product description |
Request
curl -X POST "https://studio.easel.engineering/api/v1/products/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-12345" \
-d '{
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt"
}'
Optional Headers:
Idempotency-Key: Unique string to prevent duplicate product creation (see Idempotency)
Response
Returns the created product.
Status: 201 Created
{
"id": "pro_d0b6fmv28q6vn14peun0",
"name": "Premium T-Shirt",
"status": "draft",
"description": "High-quality cotton t-shirt",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10: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": "Product name is required",
"code": "MISSING_FIELD"
}
Failed to create product
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Get Product
Retrieve a single product by its public ID.
Endpoint: GET /api/v1/products/{id}/
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/" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"id": "pro_d0b6fmv28q6vn14peun0",
"name": "Premium T-Shirt",
"status": "active",
"description": "High-quality cotton t-shirt",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z"
}
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"
}
Update Product
Update an existing product's name, description, or status.
Endpoint: PUT /api/v1/products/{id}/
Permission Required: Write
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
Request Body
{
"name": "Premium T-Shirt - Updated",
"status": "active",
"description": "Updated high-quality cotton t-shirt"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Product name |
status |
string | Yes | Product status: draft, active, or archived |
description |
string | No | Product description |
Request
curl -X PUT "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-67890" \
-d '{
"name": "Premium T-Shirt - Updated",
"status": "active",
"description": "Updated high-quality cotton t-shirt"
}'
Optional Headers:
Idempotency-Key: Unique string to prevent duplicate product updates (see Idempotency)
Response
Returns the updated product.
Status: 200 OK
{
"id": "pro_d0b6fmv28q6vn14peun0",
"name": "Premium T-Shirt - Updated",
"status": "active",
"description": "Updated high-quality cotton t-shirt",
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T11:30: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": "Product name is required",
"code": "MISSING_FIELD"
}
Invalid status
Status: 400 Bad Request
{
"error": "Status must be 'draft', 'active', or 'archived'",
"code": "INVALID_FIELD"
}
Product not found
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Failed to update product
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Duplicate Product
Copy a product and its variants into a new draft product.
Endpoint: POST /api/v1/products/{id}/duplicate/
Permission Required: Write
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Product public ID (e.g., pro_d0b6fmv28q6vn14peun0) |
Request
curl -X POST "https://studio.easel.engineering/api/v1/products/pro_d0b6fmv28q6vn14peun0/duplicate/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-13579"
Response
Status: 201 Created
{
"id": "pro_new1fmv28q6vn14peun0"
}
Error Responses
Product not found
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Too many copies
Status: 400 Bad Request
{
"error": "Invalid input",
"code": "INVALID_FIELD"
}
Failed to duplicate product
Status: 500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
Product Object
Fields
| Field | Type | Description |
|---|---|---|
id |
string | Product public ID |
name |
string | Product name |
status |
string | Product status: draft, active, archived |
description |
string|null | Product description |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |
Product Status Values
draft- Product is being configured, not visible to customersactive- Product is available for purchasearchived- Product is no longer available but preserved for historical data
Fulfillment Type
The fulfillment type is set on the product and shown on its variants. Products
created through the API are physical. Digital variants carry a downloadable
file, which you manage with the Digital Files endpoints.