Create Product
Create a new rental product.
Endpointโ
POST /v1/products
Authenticationโ
Requires an API key with the products:write scope.
Request Bodyโ
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Product name (max 255 characters) |
sku | string | No | Stock keeping unit (must be unique) |
brief_description | string | No | Short description |
long_description | string | No | Full description |
category_id | integer | No | Primary category ID. Use category_ids to put the product in multiple categories. |
category_ids | integer[] | No | Put the product in multiple categories (primary first). The first id becomes the primary category (also returned as category). Takes precedence over category_id. |
status | string | No | active, draft (default: draft) |
price_applies | string | No | yearRound or seasonal (default: yearRound) |
price_structure | string | No | flat or schedule (default: flat) |
schedule_rate_mode | string | No | How schedule rows are read: total (each row is the total price for that duration - default) or perUnit (each row is a per-day/hour/week rate that applies from that duration on; total = rate x duration); perBooking charges one amount per rented unit for the whole booking, regardless of length (use one year-round schedule row) |
inventory | boolean | No | Enable inventory tracking (default: false) |
inventory_tracking | string | No | Tracking type: group or item (default: group) |
booking_mode | string | No | instant (default) or request. See Booking Requests |
allow_shortage | boolean | No | Keep taking bookings after on-hand stock reaches zero (default: false). See Keep selling when sold out |
max_shortage | integer|null | No | How many units past on-hand stock may be sold for any overlapping window (min 1). One shared budget for the whole product, not per variation. Omit or send null with allow_shortage true for an allowance of 1 unit. Ignored when allow_shortage is false |
bundle_only | boolean | No | Only available in bundles (default: false) |
require_participants | boolean|null | No | Collect each participant's details at checkout. true = always, false = never, null or omitted = follow the shop-wide default (default: follow shop default) |
participants_per_unit | integer | No | How many people use one unit โ a 2-person kayak = 2. Each person gives details and signs waivers at checkout. 1โ10 (default: 1) |
min_rental_value | integer | No | Minimum rental period value. Use 0 for no minimum or null to follow the shop default. |
min_rental_unit | string | No | Minutes, Hours, Days |
max_rental_value | integer | No | Maximum rental period value |
max_rental_unit | string | No | Minutes, Hours, Days |
min_booking_notice | boolean | No | Enable a per-product minimum booking notice (lead time). When true, send min_booking_notice_value, same_day_cutoff_time or both. |
min_booking_notice_value | integer | No | Minimum notice value. 0 opts this product out of the supplier default. Required when min_booking_notice is true and no same_day_cutoff_time is sent. |
min_booking_notice_unit | string | No | Minutes, Hours, Days. Required with min_booking_notice_value. |
same_day_cutoff_time | string|null | No | Same-day cut-off in the shop's time zone, 24-hour "HH:MM" such as "08:30". Online bookings for that day close at this time; later days are not affected. A session that starts earlier closes at its start. Works alongside the notice length, and the stricter one wins. Sending it turns min_booking_notice on. |
Pricing Rules
To set prices for the product, use the Product Pricing endpoint after creating the product.
Example Requestโ
curl -X POST "https://app.equipdash.com/api/v1/products" \
-H "Authorization: Bearer eqd_live_abc123xyz789..." \
-H "Content-Type: application/json" \
-d '{
"name": "Stand Up Paddleboard",
"sku": "SUP-001",
"brief_description": "Inflatable SUP with paddle and pump",
"category_id": 3,
"status": "active",
"price_applies": "yearRound",
"price_structure": "flat",
"inventory": true,
"inventory_tracking": "group",
"allow_shortage": true,
"max_shortage": 2,
"min_rental_value": 2,
"min_rental_unit": "Hours"
}'
Responseโ
Success (201 Created)โ
{
"data": {
"id": 15,
"name": "Stand Up Paddleboard",
"sku": "SUP-001",
"status": "active",
"brief_description": "Inflatable SUP with paddle and pump",
"long_description": null,
"category": {
"id": 3,
"name": "Water Sports"
},
"pricing": {
"applies": "yearRound",
"structure": "flat",
"rate_mode": "total",
"uses_template": false,
"rules": []
},
"rental_constraints": {
"min": { "value": 2, "unit": "Hours" },
"max": null
},
"buffer_time": null,
"inventory": true,
"inventory_tracking": "group",
"allow_shortage": true,
"max_shortage": 2,
"has_variations": false,
"bundle_only": false,
"require_participants": false,
"participants_per_unit": 1,
"variations": [],
"default_image": null,
"created_at": "2026-01-15T12:00:00+00:00",
"updated_at": "2026-01-15T12:00:00+00:00"
},
"meta": {
"request_id": "req_def456",
"timestamp": "2026-01-15T12:00:00+00:00"
}
}
Errorsโ
| Status | Code | Description |
|---|---|---|
| 401 | authentication_required | No API key provided |
| 401 | invalid_api_key | Invalid API key |
| 403 | insufficient_scope | API key lacks products:write scope |
| 422 | validation_error | Invalid request data |
Validation Error Exampleโ
{
"error": {
"code": "validation_error",
"message": "The given data was invalid.",
"details": {
"name": ["The name field is required."],
"sku": ["The sku has already been taken."]
}
},
"meta": {
"request_id": "req_xyz789"
}
}