Booking items represent the programmes, courses, or events that users can apply to. The API exposes a resolved view of booking items with their merged option tree, workflows, eligibility rules, and audit history.
A booking item can be retrieved using its id:
>>> response = requests.get(
... 'https://api.kaizenep.com/v2/booking-items/effa9413-ee11-49a2-9e36-98397b878c2a',
... params={'includeParts': 'all'},
... headers=headers
... )
>>> response.json()
{
"_id": "effa9413-ee11-49a2-9e36-98397b878c2a",
"name": "Clinical Skills Exam",
"state": "published",
"securityContext": {
"roles": []
},
"option": {
"id": "effa9413-ee11-49a2-9e36-98397b878c2a",
"title": "Clinical Skills Exam",
"bookableType": "cover",
"path": ["effa9413-ee11-49a2-9e36-98397b878c2a"],
"breadcrumbs": [
{"id": "effa9413-ee11-49a2-9e36-98397b878c2a", "title": "Clinical Skills Exam"}
],
"state": {"id": "published", "name": "Published"},
"capacities": {"availableCapacity": 10},
"pricing": {"price": 100.0, "currency": "CAD", "method": ["1868df13-..."]},
"metadata": [{"key": "EXAM_CODE", "value": "CSE-2026-01"}],
"summary": {
"price": {"min": 100.0, "max": 100.0, "currency": "CAD"},
"bookingDates": {},
"bookingWindow": {},
"openOptions": 2
},
"workflowId": "w-446gsumpbi",
"eligibilityId": "cb6239c9958fbdfc3d2a3b1c9027bd07",
"options": [
{
"id": "5e89a487-8e09-4bef-95e9-38162fd8de3b",
"title": "Clinical Skills Exam - Session 1",
"bookableType": "bookable",
"path": ["effa9413-...", "5e89a487-..."],
"state": {"id": "published", "name": "Published"},
"pricing": {"price": 100.0, "currency": "CAD"},
"workflowId": "w-446gsumpbi",
"eligibilityId": "cb6239c9958fbdfc3d2a3b1c9027bd07",
"options": []
},
...
]
},
"workflows": [...],
"eligibilities": [...],
"metadata": [{"key": "EXAM_CODE", "value": "CSE-2026-01"}],
"summary": {...},
"auditLog": [
{
"_id": "935bb253-01d1-4287-a319-5a4a393b3e98",
"date": "2026-05-14T09:23:34.527385+00:00",
"action": "booking_item_edit",
"actor": "exam.admin"
},
...
]
}
The response includes several sections that can be individually controlled using the
includeParts query parameter.
The content of the response can be controlled by the includeParts parameter.
Pass a comma-separated list of parts to include:
all — Includes everything listed below
options — The merged option tree (sessions resolved with inherited properties)
workflows — Full workflow definitions (states, transitions, actions, guards)
eligibilities — Eligibility rule sets used across the option tree
metadata — Key/value metadata attached to the booking item
summary — A summary of the root option (pricing range, dates, open options count)
auditlog — Audit log of actions performed on the booking item
If includeParts is omitted, all parts are returned by default.
# Fetch only the option tree and metadata
>>> response = requests.get(
... 'https://api.kaizenep.com/v2/booking-items/<id>',
... params={'includeParts': 'options,metadata'},
... headers=headers
... )
These fields are always returned regardless of includeParts:
Field |
Type |
Description |
|---|---|---|
|
string |
Unique identifier of the booking item |
|
string |
Display name of the booking item |
|
string |
Current state (e.g. |
|
object |
Roles required to access this item |
options part)¶The option field contains the root of the resolved option tree. Each node represents
a session (option) with its properties inherited and merged from parent nodes.
Key fields on each option node:
Field |
Type |
Description |
|---|---|---|
|
string |
Option identifier |
|
string |
Resolved display title |
|
string |
Either |
|
array |
Ordered list of ancestor IDs from root to this node |
|
array |
List of |
|
object |
|
|
object |
Available capacity information |
|
object |
Price, currency, and payment method references |
|
string |
Reference to the workflow definition in the |
|
string |
Hash reference to the eligibility rule in the |
|
array |
Child option nodes (recursive tree structure) |
Note
The form and eligibility objects are stripped from the option tree in the
list response for performance. Use the individual option endpoint to retrieve full
details including form fields and eligibility rules.
workflows part)¶An array of workflow definitions referenced by workflowId in the option tree.
Each workflow describes how a booking progresses through states, what form fields are
available at each stage, and what transitions (actions) are possible.
Structure overview:
{
"id": "w-446gsumpbi",
"name": "Clinical Skills Exam Workflow",
"form": {
"id": "w-446gsumpbi",
"name": "Clinical Skills Exam Workflow",
"initial": {
"state": "ws-ri2663t3f2",
"roles": ["org_medschool:candidate"],
"actions": []
},
"states": [...],
"transitions": [...],
"fields": [...]
}
}
Each state defines which roles can see/edit which fields and which transitions are available:
{
"id": "ws-ri2663t3f2",
"name": "DRAFT",
"roles": [
{
"role": "org_medschool:candidate",
"group": {
"wff-ztm8jbzujd": "edit",
"wff-zo35g8ebeo": "edit",
"wff-5sx7numpou": "view"
},
"transitions": ["wt-ac4dfrszrx"],
"canDelete": false
},
{
"role": "org_medschool:exam-admin",
"group": {"wff-ztm8jbzujd": "view"},
"transitions": [],
"canDelete": false
}
]
}
Field |
Type |
Description |
|---|---|---|
|
string |
State identifier (referenced by transitions) |
|
string |
Display name of the state (e.g. DRAFT, SUBMITTED, PAID) |
|
array |
Per-role permissions for this state |
|
string |
Role identifier (e.g. |
|
object |
Field permissions — maps field ID → |
|
array |
Transition IDs this role is allowed to trigger from this state |
|
boolean |
Whether this role can delete the booking in this state |
Transitions define how a booking moves from one state to another, including validation, required actions, and guards:
{
"id": "wt-ac4dfrszrx",
"name": "Submit booking",
"sources": ["ws-ri2663t3f2"],
"destination": "ws-uhth56zgsh",
"actions": [
{
"action": "fill_in_fields",
"data": {
"fields": [
{"id": "wff-zo35g8ebeo", "required": true},
{"id": "wff-5mdi71hykg", "required": true}
]
}
},
{"action": "collect_payment", "data": {}},
{"action": "reserve_seat", "data": {"ttl": "10"}},
{"action": "confirm_booking", "data": {}}
],
"guards": [
{
"guard": "field_guard",
"data": {
"field": "wff-zo35g8ebeo",
"op": "has_all",
"value": ["23d6iwmewja"]
}
}
],
"message": "",
"allowInvalidForm": false,
"autoTransition": false,
"requireConfirmation": false
}
Field |
Type |
Description |
|---|---|---|
|
string |
Transition identifier |
|
string |
Display name (e.g. “Submit”, “Retract”, “Approve”) |
|
array |
State IDs from which this transition can be triggered |
|
string |
Target state ID after the transition completes |
|
array |
Ordered list of actions executed during the transition |
|
array |
Conditions that must be met before the transition is allowed |
|
string |
Optional message displayed to the user during transition |
|
boolean |
If true, transition is allowed even if required fields are incomplete |
|
boolean |
If true, transition fires automatically when conditions are met |
|
boolean |
If true, user must confirm before the transition executes |
Common transition actions:
fill_in_fields — Requires specified fields to be filled (with optional required flag)
collect_payment — Triggers payment collection
reserve_seat — Reserves capacity with a TTL (time-to-live in minutes)
confirm_booking — Marks the booking as confirmed
refund_payments — Issues refunds with configurable refund options (full, partial, custom)
Guards:
Guards prevent a transition from being triggered unless conditions are met:
field_guard — Checks a field value (operators: has_all, has_any, equals, etc.)
The fields array defines all form fields available in the workflow:
[
{
"id": "wff-ztm8jbzujd",
"fieldType": "string",
"type": "field",
"options": {
"required": true,
"label": "Candidate full name",
"meta": {}
},
"validators": [],
"asyncValidators": []
},
{
"id": "wff-zo35g8ebeo",
"fieldType": "select",
"type": "field",
"options": {
"required": false,
"label": "Assessment track",
"meta": {},
"categories": [
{"_id": "23d6iwmewja", "name": "General medicine"},
{"_id": "k1b3us34lvj", "name": "Emergency medicine"}
]
},
"validators": [],
"asyncValidators": []
}
]
Field |
Type |
Description |
|---|---|---|
|
string |
Field identifier (referenced in state |
|
string |
Input type: |
|
string |
Always |
|
boolean |
Whether the field is required by default |
|
string |
Display label for the field |
|
array |
For |
|
array |
Synchronous validation rules |
|
array |
Asynchronous validation rules (e.g. server-side checks) |
eligibilities part)¶An array of eligibility rule sets referenced by eligibilityId in the option tree.
The rules field is returned as a parsed JSON object (not a string):
[
{
"id": "32e2693e-4984-442f-97d7-12ed31c747c3",
"name": "Exam registration eligibility",
"rules": {
"op": "and",
"description": "Clinical Skills Exam eligibility",
"affirmative": true,
"args": [
{
"op": "hasRole",
"description": "Must hold candidate role",
"affirmative": true,
"options": {"roles": ["org_medschool:candidate"]}
},
{
"op": "hasRelation",
"description": "Must be linked to candidate cohort",
"affirmative": true,
"options": {
"relation": "9c595151-...",
"relationCategories": ["454462fd-..."]
}
},
{
"op": "hasEvent",
"description": "Must have completed prerequisite event in range",
"affirmative": true,
"options": {
"start": "2026-04-01",
"end": "2026-05-16"
}
}
]
}
}
]
The rules tree is a recursive structure of logical operators:
Field |
Type |
Description |
|---|---|---|
|
string |
Operator: |
|
string |
Human-readable description of the rule |
|
boolean |
If false, the rule is negated |
|
array |
Child rules (for |
|
object |
Condition-specific parameters (for leaf operators) |
metadata part)¶Key/value pairs attached to the booking item:
[
{"key": "EXAM_CODE", "value": "CSE-2026-01"}
]
summary part)¶A summarised view of the root option, useful for listing pages:
{
"price": {"min": 100.0, "max": 100.0, "currency": "CAD"},
"bookingDates": {},
"bookingWindow": {},
"openOptions": 2
}
auditlog part)¶A chronological list of actions performed on the booking item, sorted by date (oldest first):
[
{
"_id": "a1b2c3d4-...",
"date": "2026-05-14T09:23:34.527385+00:00",
"action": "booking_item_edit",
"actor": "exam.admin",
"source": "web"
}
]
Each entry contains:
Field |
Type |
Description |
|---|---|---|
|
string |
Audit log entry identifier |
|
string |
ISO 8601 timestamp of the action |
|
string |
Action type (e.g. |
|
string |
User who performed the action |
|
string |
Target user (if applicable) |
|
string |
Original actor if action was performed via masquerade |
|
string |
Source of the action (e.g. |
|
object |
Additional context data specific to the action |
Individual options can be retrieved with full details (including form fields and eligibility rules that are stripped from the tree response):
>>> response = requests.get(
... 'https://api.kaizenep.com/v2/booking-items/<booking_item_id>/options/<option_id>',
... headers=headers
... )
>>> response.json()
{
"id": "5e89a487-8e09-4bef-95e9-38162fd8de3b",
"title": "Clinical Skills Exam - Session 1",
"bookableType": "bookable",
"state": {"id": "published", "name": "Published"},
"pricing": {"price": 100.0, "currency": "CAD"},
"form": {
"id": "w-446gsumpbi",
"fields": [...]
},
"eligibility": {
"rules": "{...}",
"hash": "cb6239c9958fbdfc3d2a3b1c9027bd07"
},
"workflow": {
"id": "w-446gsumpbi",
"state": "draft",
"name": "Clinical Skills Exam Workflow"
},
"options": []
}
This endpoint returns the full option data including form and eligibility
which are not present in the tree view.