Enroll in a Program
Enroll a customer in every session of a bookable series — a program in the product UI — with one call. This is the same action as a customer buying the program on the booking widget or staff selling it at POS: it books the whole program in one booking — one experience line per session, with series_id set — and returns that booking.
Endpoint
POST /v1/series/{id}/enroll
Authentication
Requires a live or test API key with series:write scope.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Series ID (must be bookable) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
customer_id | integer | Yes | The customer to enroll in the program |
quantity | integer | No | Spots reserved on every session line — 1–50, default 1 |
participants | array | No | Participant customers, as [{ "customer_id": 457, "rate_category_id": 3 }]. rate_category_id selects the rate type (e.g. adult vs child) for programs with per-rate-type fixed pricing. |
extras | array | No | Add-ons for the whole program, as [{ "extra_id": 31, "quantity": 2 }]. Each is charged once for the program, not per session, and saved on the first session it is offered on. A per-person add-on is held to the number of people enrolling. The add-ons a program sells are listed in extras on Get Series. An add-on the program does not sell is refused with enrollment_failed. |
Example Request
curl -X POST "https://app.equipdash.com/api/v1/series/1/enroll" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": 456,
"quantity": 2,
"participants": [
{ "customer_id": 457, "rate_category_id": 3 }
],
"extras": [
{ "extra_id": 31, "quantity": 2 }
]
}'
Response
Success (201 Created)
Returns the created booking in the standard booking shape — one booking (type: "experience", status: "confirmed", series_id set) with one experience line per session of the program. Trimmed example:
{
"data": {
"id": 9010,
"type": "experience",
"line_types": ["experience"],
"status": "confirmed",
"payment_status": "unpaid",
"source": "API",
"series_id": 1,
"currency": "USD",
"customer": {
"id": 456,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "0412345678",
"phone_country_code": "+61"
},
"experiences": [
{
"experience_id": 12,
"schedule_id": 501,
"quantity": 2
},
{
"experience_id": 12,
"schedule_id": 502,
"quantity": 2
},
{
"experience_id": 12,
"schedule_id": 503,
"quantity": 2
}
],
"created_at": "2026-07-22T10:00:00+00:00",
"updated_at": "2026-07-22T10:00:00+00:00"
},
"meta": {
"request_id": "req_abc123"
}
}
See Get Booking for the full booking shape (pricing, payments, participants, waivers).
Errors
| Status | Code | Description |
|---|---|---|
| 401 | authentication_required | No API key provided |
| 403 | insufficient_scope | API key lacks series:write scope |
| 403 | forbidden | Series belongs to a different supplier |
| 404 | resource_not_found | Series does not exist |
| 422 | validation_failed | customer_id missing/invalid, quantity outside 1–50, or a participant entry without a customer_id |
| 422 | business error | The program is cancelled, the customer was not found, a session slot is in the past, or there are not enough spots on a session date (the message names the date, e.g. Not enough spots on Sep 8, 2026) |
Notes
- One call books the whole program: a single booking with one experience line per session — not one booking per session. The booking total is the program rate, per the program's pricing option (the sum of the sessions, or the fixed rate — see Pricing).
- Capacity is checked on every session slot before the booking is created; if any session can't fit the requested spots, nothing is booked.