List Courses
Returns a paginated list of all courses of the company.
Required license
This endpoint requires the company's course license.
Request
GET /api/oauth/v2/resource/courses
Header
| Header | Value |
|---|---|
Authorization | Bearer {access_token} |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | No | Course type (default: all three course types). Allowed values: course, course_once, course_service. Special value all is an alias for the default. |
status | string | No | Filters by status, combinable as a comma-separated list. Allowed values: active (not archived), archived. Default: all (all values). See Conventions. |
offset | integer | No | Start position (default: 0) |
limit | integer | No | Number of results (default: 50, max: 200) |
Note: This endpoint always requires the scopes
coursesandusers. For the attendee list (attendees), the scopecustomersis additionally required.
Note on attendees: Without the
customersscope, theattendeeskey is missing from the response entirely — it is not[]and notnull. The numbercurrentAttendeesis always included.
Note: An archived course is the deletion form of the course. There is no deletion timestamp and therefore no
deletedSince— the filterstatus=archivedis the way to retrieve deleted courses.
Note: There is no incremental sync for courses. A course does not carry timestamps, so there is no
createdSinceand noupdatedSince.
Note: Without a
statusfilter, this endpoint sorts by internal ID ascending, see Conventions.
Response
Success (200 OK)
Example: with scope customers
{
"data": [
{
"id": "c3d4e5f6-a7b8-9012-cdef-012345678901",
"name": "Yoga Anfänger",
"type": "course",
"archived": false,
"internalNumber": "K-2026-014",
"description": "Yoga für Einsteiger",
"information": "Bitte bequeme Kleidung mitbringen",
"maxAttendees": 20,
"currentAttendees": 12,
"color": "#74AFAD",
"price": "120.00",
"priceNet": "100.00",
"vat": "20.00",
"sort": 0,
"billStatus": "open",
"isOnlineBookable": true,
"directBooking": false,
"bookingBefore": "P1D",
"storno": "PT24H",
"category": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"instructors": ["d4e5f6a7-b8c9-0123-defa-123456789012"],
"location": "e5f6a7b8-c9d0-1234-efab-234567890123",
"tenancies": ["9a8b7c6d-5e4f-3210-9876-543210fedcba"],
"attendees": ["b2c3d4e5-f6a7-8901-bcde-f12345678901"]
}
],
"meta": {
"total": 42,
"offset": 0,
"limit": 50
}
}Example: without scope customers
{
"data": [
{
"id": "c3d4e5f6-a7b8-9012-cdef-012345678901",
"name": "Yoga Anfänger",
"type": "course",
"archived": false,
"internalNumber": "K-2026-014",
"description": "Yoga für Einsteiger",
"information": "Bitte bequeme Kleidung mitbringen",
"maxAttendees": 20,
"currentAttendees": 12,
"color": "#74AFAD",
"price": "120.00",
"priceNet": "100.00",
"vat": "20.00",
"sort": 0,
"billStatus": "open",
"isOnlineBookable": true,
"directBooking": false,
"bookingBefore": "P1D",
"storno": "PT24H",
"category": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"instructors": ["d4e5f6a7-b8c9-0123-defa-123456789012"],
"location": "e5f6a7b8-c9d0-1234-efab-234567890123",
"tenancies": ["9a8b7c6d-5e4f-3210-9876-543210fedcba"]
}
],
"meta": {
"total": 42,
"offset": 0,
"limit": 50
}
}Note: In the second example, the
attendeeskey is missing — it is not present, not[], and notnull.currentAttendeesis still included.
Response fields
| Field | Type | Description |
|---|---|---|
data | Array | List of courses |
data[].id | string (UUID) | Unique course ID |
data[].name | string | Course name |
data[].type | string | Course type (course, course_once, course_service) |
data[].archived | boolean | true if the course is archived — the deletion form of the course |
data[].internalNumber | string | null | Internal course number |
data[].description | string | null | Course description |
data[].information | string | null | Additional information about the course |
data[].maxAttendees | integer | null | Maximum number of attendees |
data[].currentAttendees | integer | Number of active (non-canceled) attendances. attendees additionally includes canceled attendances and can therefore be longer than this number. |
data[].color | string | Color as a hex code. Falls back to the category color or to #74AFAD if no color of its own is set — never null. |
data[].price | string | Gross course price |
data[].priceNet | string | Net course price |
data[].vat | string | VAT rate in percent for this course, otherwise the company's default VAT |
data[].sort | integer | Sort position |
data[].billStatus | string | Billing status: open, invoiced, ignore, unknown |
data[].isOnlineBookable | boolean | true if the course can be booked online |
data[].directBooking | boolean | true if an online booking is confirmed immediately without approval |
data[].bookingBefore | string (ISO 8601 duration) | Latest booking time before the course starts, e.g. P1D for one day |
data[].storno | string (ISO 8601 duration) | Deadline for a free cancellation before the course starts, e.g. PT24H for 24 hours |
data[].category | string (UUID) | null | Course category. Look up via GET /services/categories/{uuid} |
data[].instructors | Array (string, UUID) | UUIDs of the instructors. Look up via GET /users/{uuid} |
data[].location | string (UUID) | null | Course location |
data[].tenancies | Array (string, UUID) | IDs of the tenancies this course is available for — empty without the Tenancies add-on |
data[].attendees | Array (string, UUID) | UUIDs of all attendances, including canceled ones. Only included when the customers scope is present — without this scope the key is missing entirely, it is not [] and not null. Details per attendance via Attendee Details or collected via List Attendees |
meta.total | integer | Upper bound of the match count before permission filtering — not the number of actually accessible courses. count(data) can be smaller than limit even though total promises more. |
meta.offset | integer | Current start position |
meta.limit | integer | Number of returned entries |
curl -X GET "https://my.offisy.at/api/oauth/v2/resource/courses?type=all&status=all&offset=0&limit=50" \
-H "Authorization: Bearer {access_token}"Possible errors
| Status | Code | Description |
|---|---|---|
| 400 | validation_error | type or status contains an invalid value |
| 401 | invalid_client | Invalid or missing access token |
| 403 | insufficient_scope | Scope courses or users is missing |
| 403 | insufficient_scope | Course license not present |