Hydra is now in beta|Get started free|Follow our journey on X.com

Products API
On this page

Products

Products are the core resource in Hydra. Each product has a title, handle (URL slug), description, and status. Products can have up to 5 options (e.g. Size, Color) and 250 variants representing each combination.

Base URL: https://api.hydrajs.dev

Endpoints

Method Path Auth Description
GET /v1/products Publishable List products
POST /v1/products Secret Create a product
POST /v1/products/batch Secret Batch create products
GET /v1/products/{id} Publishable Get a product
PATCH /v1/products/{id} Secret Update a product
DELETE /v1/products/{id} Secret Delete a product (soft)
POST /v1/products/{id}/duplicate Secret Duplicate a product
GET /v1/products/{id}/variants Publishable List variants
POST /v1/products/{id}/variants Secret Create a variant
POST /v1/products/{id}/variants/generate Secret Generate variants from combinations
GET /v1/products/{id}/images Publishable List images
POST /v1/products/{id}/images Secret Upload an image
POST /v1/products/{id}/images/attach Secret Attach existing images

List products

GET /v1/products

Returns a paginated list of products. Supports search, filtering, sorting, and sparse fieldsets.

Query parameters

Parameter Type Default Description
limit integer 25 Results per page (1–100)
cursor string - Pagination cursor from a previous response
sort string created_at Sort field: created_at, updated_at, title
order string desc Sort direction: asc, desc
status string - Filter by status: active, draft, archived, preorder, coming_soon, discontinued
collection_id string - Filter by collection membership
search string - Full-text search with typo correction
created_after ISO 8601 - Filter: created after this date
created_before ISO 8601 - Filter: created before this date
currency string - 3-letter ISO currency code for price conversion
fields string - Comma-separated fields to return

Request

curl https://api.hydrajs.dev/v1/products?status=active&limit=10 \
  -H "Authorization: Bearer pk_live_YOUR_KEY"

Response 200

{
	"data": [
		{
			"id": "prod_abc123",
			"title": "Classic T-Shirt",
			"handle": "classic-t-shirt",
			"status": "active",
			"product_type": "Apparel",
			"brand": "Hydra Basics",
			"created_at": "2026-01-15T10:30:00Z",
			"updated_at": "2026-08-01T14:22:00Z"
		}
	],
	"pagination": {
		"cursor": "eyJ0IjoiMjAyNi...",
		"has_more": true,
		"total": 42
	}
}

Pagination

All list endpoints use cursor-based pagination. Pass the cursor value from the response to fetch the next page.


Get a product

GET /v1/products/{id}

Returns a single product by ID. Use expand to include related resources inline.

Query parameters

Parameter Type Description
expand string Comma-separated: variants, images, prices
currency string 3-letter ISO currency code for price conversion
fields string Comma-separated fields to return

Request

curl https://api.hydrajs.dev/v1/products/prod_abc123?expand=variants,images \
  -H "Authorization: Bearer pk_live_YOUR_KEY"

Response 200

{
	"data": {
		"id": "prod_abc123",
		"title": "Classic T-Shirt",
		"handle": "classic-t-shirt",
		"subtitle": null,
		"description": "A comfortable everyday t-shirt.",
		"status": "active",
		"product_type": "Apparel",
		"brand": "Hydra Basics",
		"google_product_category": "Apparel & Accessories > Clothing > Shirts & Tops",
		"hs_code": "6109.10",
		"country_of_origin": "US",
		"fulfillment_type": "physical",
		"tags": ["basics", "cotton"],
		"options": [{ "name": "Size", "values": ["S", "M", "L", "XL"], "position": 0 }],
		"specifications": [
			{ "label": "Material", "value": "100% Cotton" },
			{ "label": "Weight", "value": "180 GSM" }
		],
		"seo": {
			"title": "Classic T-Shirt | Hydra Basics",
			"description": "A comfortable everyday t-shirt in 100% cotton."
		},
		"metadata": {},
		"variants": [
			{
				"id": "var_def456",
				"title": "S",
				"sku": "TSH-S",
				"barcode": null,
				"price": 2999,
				"sale_price": null,
				"cost": 800,
				"inventory_quantity": 50,
				"weight": 180,
				"weight_unit": "g",
				"hs_code": null,
				"country_of_origin": null,
				"options": { "Size": "S" },
				"position": 0
			}
		],
		"images": [
			{
				"id": "img_ghi789",
				"src": "https://cdn.hydrajs.dev/stores/store_xxx/img_ghi789.webp",
				"alt": "Classic T-Shirt front view",
				"width": 1200,
				"height": 1600,
				"position": 0
			}
		],
		"created_at": "2026-01-15T10:30:00Z",
		"updated_at": "2026-08-01T14:22:00Z"
	}
}

Internal notes

The internal_notes field is only returned for secret key requests. Publishable keys never see this field.


Create a product

POST /v1/products

Creates a new product. Returns the created product with 201.

Request body

Field Type Required Description
title string Yes Product title (max 255 chars)
handle string No URL slug. Auto-generated from title if omitted
subtitle string No Short subtitle (max 65 chars). Requires subtitle extension
description string No Markdown description (max 10,000 chars)
status string No draft (default), active, archived, preorder, coming_soon, discontinued
preorder_expected_date string No ISO 8601 date (e.g. 2026-12-01). Required when status is preorder
product_type string No Free-text category (max 100 chars)
brand string No Brand name (max 100 chars)
google_product_category string No Google taxonomy path (max 500 chars)
hs_code string No Harmonized System code for customs (max 20 chars)
country_of_origin string No ISO 3166-1 alpha-2 country code (2 letters, e.g. US)
fulfillment_type string No physical (default), digital, service
internal_notes string No Private notes (max 5,000 chars)
qty_step integer No Minimum quantity increment. Requires qty_step extension
tags string[] No Array of tags (max 250 tags, each max 100 chars)
options object[] No Product options (max 5). Each: name, values[], position
variants object[] No Initial variants with pricing and inventory
specifications object[] No Key-value specs (max 50). Each: label, value
seo object No SEO metadata: title, description
metadata object No Arbitrary key-value pairs (max 50 keys)

Product statuses

Products with preorder status can be added to cart (requires preorder_expected_date). Products with coming_soon or discontinued status are visible on the storefront but cart/checkout is blocked.

Request

curl -X POST https://api.hydrajs.dev/v1/products \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Classic T-Shirt",
    "status": "draft",
    "product_type": "Apparel",
    "tags": ["basics", "cotton"],
    "variants": [
      {
        "title": "Default",
        "price": 2999,
        "inventory_quantity": 100
      }
    ]
  }'

Response 201

Returns the full product object (same shape as Get a product).


Batch create products

POST /v1/products/batch

Creates multiple products in a single atomic request. All products are created within a transaction - if any product fails validation, none are created.

Request body

Field Type Required Description
products object[] Yes Array of product objects (1–50). Each object accepts the same fields as Create a product

All-or-nothing

If any product in the batch has invalid data or a conflicting handle, the entire batch is rejected. No products are created.

Request

curl -X POST https://api.hydrajs.dev/v1/products/batch \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {
        "title": "Classic T-Shirt",
        "status": "draft",
        "variants": [{ "title": "Default", "price": 2999 }]
      },
      {
        "title": "Slim Jeans",
        "product_type": "Apparel",
        "tags": ["denim"],
        "variants": [{ "title": "Default", "price": 5999 }]
      }
    ]
  }'

Response 201

{
	"data": [
		{
			"id": "prod_abc123",
			"title": "Classic T-Shirt",
			"handle": "classic-t-shirt",
			"status": "draft",
			"variants": [{ "id": "var_def456", "title": "Default", "price": 2999 }]
		},
		{
			"id": "prod_xyz789",
			"title": "Slim Jeans",
			"handle": "slim-jeans",
			"status": "draft",
			"variants": [{ "id": "var_ghi012", "title": "Default", "price": 5999 }]
		}
	]
}

Rate limiting

A batch request counts as a single API call toward your rate limit and monthly quota, regardless of how many products are in the batch.


Update a product

PATCH /v1/products/{id}

Partially updates a product. Send only the fields you want to change. Returns the updated product.

Request body

All fields from Create a product are accepted, and all are optional. Additional fields:

Field Type Description
create_redirect boolean If true and handle changed, creates a URL redirect from the old handle

Tags replace, not merge

Sending tags replaces the entire array. To add a tag, fetch the current tags, append, and send the full list.

Request

curl -X PATCH https://api.hydrajs.dev/v1/products/prod_abc123 \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Premium T-Shirt",
    "status": "active",
    "tags": ["premium", "cotton", "new-arrival"]
  }'

Response 200

Returns the full updated product object.


Delete a product

DELETE /v1/products/{id}

Soft-deletes a product. The product is hidden from all queries and its handle is freed for reuse. Permanently purged after 30 days.

Request

curl -X DELETE https://api.hydrajs.dev/v1/products/prod_abc123 \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 204

Empty body.


Duplicate a product

POST /v1/products/{id}/duplicate

Creates a copy of an existing product with a new title and handle.

Request body

Field Type Required Description
title string Yes Title for the new product
include_variants boolean No Copy variants (default: true)
include_images boolean No Copy images (default: true)

Request

curl -X POST https://api.hydrajs.dev/v1/products/prod_abc123/duplicate \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Classic T-Shirt (Copy)" }'

Response 201

Returns the new product object.


List variants

GET /v1/products/{id}/variants

Returns all variants for a product.

Request

curl https://api.hydrajs.dev/v1/products/prod_abc123/variants \
  -H "Authorization: Bearer pk_live_YOUR_KEY"

Response 200

{
	"data": [
		{
			"id": "var_def456",
			"title": "S",
			"sku": "TSH-S",
			"price": 2999,
			"sale_price": null,
			"cost": 800,
			"inventory_quantity": 50,
			"options": { "Size": "S" },
			"position": 0
		}
	]
}

Create a variant

POST /v1/products/{id}/variants

Adds a variant to a product.

Request body

Field Type Required Description
title string Yes Variant title (max 255 chars)
sku string No Stock keeping unit (max 100 chars)
barcode string No Barcode / UPC (max 100 chars)
price integer Yes Price in cents (e.g. 2999 = $29.99)
sale_price integer No Original price in cents for sale display
inventory_quantity integer No Stock count (default: 0)
weight integer No Weight in weight_unit units
weight_unit string No g (default), kg, oz, lb
hs_code string No Harmonized System code for customs (max 20 chars)
country_of_origin string No ISO 3166-1 alpha-2 country code (2 letters, e.g. US)
options object No Option values: { "Size": "M", "Color": "Blue" }

Response 201

Returns the created variant object.


Generate variants

POST /v1/products/{id}/variants/generate

Bulk-creates variants from option combinations. Maximum 250 variants per product.

Request body

Field Type Required Description
combinations object[] Yes Array of option maps: [{ "Size": "S", "Color": "Red" }, ...]

Response 201

{
	"data": {
		"variants": [
			{
				"id": "var_xxx",
				"title": "S / Red",
				"price": 0,
				"options": { "Size": "S", "Color": "Red" }
			}
		]
	}
}

List images

GET /v1/products/{id}/images

Returns all images for a product, ordered by position.

Response 200

{
	"data": [
		{
			"id": "img_ghi789",
			"src": "https://cdn.hydrajs.dev/stores/store_xxx/img_ghi789.webp",
			"alt": "Front view",
			"width": 1200,
			"height": 1600,
			"position": 0,
			"lqip": "base64..."
		}
	]
}

Upload an image

POST /v1/products/{id}/images

Uploads an image file and attaches it to the product. Send as multipart/form-data.

Form fields

Field Type Required Description
file File Yes Image file (JPEG, PNG, WebP, GIF, AVIF, HEIC). Max 10 MB
lqip string No Base64 ThumbHash for low-quality image placeholder

Request

curl -X POST https://api.hydrajs.dev/v1/products/prod_abc123/images \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -F "file=@photo.jpg"

Response 201

Returns the created image object.


Attach existing images

POST /v1/products/{id}/images/attach

Attaches images from the media library to a product without re-uploading.

Request body

Field Type Required Description
image_ids string[] Yes Array of image IDs to attach

Request

curl -X POST https://api.hydrajs.dev/v1/products/prod_abc123/images/attach \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "image_ids": ["img_aaa", "img_bbb"] }'

Response 201

Returns the attached image objects.


Webhooks

Product changes fire the following webhook events:

Event Trigger
product.created Product created or duplicated
product.updated Product fields updated
product.deleted Product soft-deleted

See Webhooks for subscription setup.


The product object

Field Type Description
id string Unique ID (prefix: prod_)
title string Product title
handle string URL-safe slug
subtitle string | null Short subtitle
description string | null Markdown-formatted text
status string draft, active, archived, preorder, coming_soon, discontinued
preorder_expected_date string | null ISO 8601 date. Set when status is preorder
product_type string | null Free-text category
brand string | null Brand name
google_product_category string | null Google taxonomy path
hs_code string | null Harmonized System code for customs
country_of_origin string | null ISO 3166-1 alpha-2 country code
fulfillment_type string physical, digital, service
internal_notes string | null Private notes (secret key only)
qty_step integer | null Minimum order quantity increment
tags string[] Product tags
options object[] Option definitions with name, values[], position
specifications object[] Key-value specs with label, value
seo object title, description
metadata object Arbitrary key-value pairs
variants object[] Expanded with ?expand=variants
images object[] Expanded with ?expand=images
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp