Productivity Report
Returns appointment duration, appointment count, turnover, and turnover per treating-user hour, groupable by treating user, resource, course, and time period.
The data basis and limitations of this section are described in the section overview — in particular, that these endpoints report on fee note services, not invoices.
Request
GET /api/oauth/v2/resource/fee-note-services/productivity
Header
| Header | Value |
|---|---|
Authorization | Bearer {access_token} |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string (ISO date) | Yes | Start of the time range |
until | string (ISO date) | Yes | End of the time range |
groupBy | string | No | Comma list from treatingUser, resource, course. Plus at most one time token (day, week, month, year). Default: treatingUser,month |
treatingUserId | string (UUID) | No | Filters by treating user |
offset | integer | No | Start position (default: 0) |
limit | integer | No | Number of results (default: 50, max: 200) |
Note on sorting: Rows come in a stable order — a repeated call with the same filter and page returns the same order. A requested time bucket (
day,week,month,year) sorts first, so time series come out chronologically.
Note on deleted patients: Fee note services of deleted patients are no longer included in productivity, just like in the Turnover Report.
Response
Success (200 OK)
{
"data": [
{
"period": "2026-03",
"treatingUser": "6f1c1a2b-3c4d-5e6f-7890-abcdef123456",
"resource": null,
"course": null,
"hasAppointment": true,
"appointmentCount": 214,
"durationMinutes": 6420,
"gross": 48200.00,
"net": 48200.00,
"turnoverPerHour": 450.47
},
{
"period": "2026-03",
"treatingUser": "6f1c1a2b-3c4d-5e6f-7890-abcdef123456",
"resource": null,
"course": null,
"hasAppointment": false,
"appointmentCount": 0,
"durationMinutes": 0,
"gross": 1250.00,
"net": 1250.00,
"turnoverPerHour": null
}
],
"meta": { "total": 26, "offset": 0, "limit": 50 }
}The second row (hasAppointment: false) shows fee note services without an appointment: they contribute to gross/net but not to durationMinutes.
Response fields
| Field | Type | Description |
|---|---|---|
data | Array | List of aggregated productivity rows |
data[].period | string | null | Time bucket, format depends on the time token in groupBy, null if no time token was requested |
data[].treatingUser | string (UUID) | null | ID of the treating user, null if not requested. Loadable via Get User |
data[].resource | string (UUID) | null | ID of the resource (can also be an OR room), null if not requested. No OAuth endpoint to load it, see Conventions |
data[].course | string (UUID) | null | ID of the course, null if not requested. Loadable via Get Course |
data[].hasAppointment | boolean | Whether the row aggregates fee note services with an appointment (true) or without one (false) |
data[].appointmentCount | integer | Number of underlying appointments |
data[].durationMinutes | integer | Summed appointment duration in minutes. 0 for rows without an appointment |
data[].gross | float | Gross amount |
data[].net | float | Net amount |
data[].turnoverPerHour | float | null | Turnover per treating-user hour (gross / (durationMinutes / 60), rounded to two decimals). null when durationMinutes = 0 |
meta.total | integer | Total number of groups |
meta.offset | integer | Current start position |
meta.limit | integer | Number of returned entries |
curl -X GET "https://my.offisy.at/api/oauth/v2/resource/fee-note-services/productivity?from=2026-01-01&until=2026-12-31&groupBy=treatingUser%2Cmonth&treatingUserId=b2c3d4e5-f6a7-8901-bcde-f01234567890&offset=0&limit=50" \
-H "Authorization: Bearer {access_token}"Possible errors
| Status | Code | Description |
|---|---|---|
| 400 | validation_error | Missing or invalid from/until, invalid dimension, more than one time token, or time range too long |
| 400 | validation_error | treatingUserId is not a valid UUID |
| 400 | invalid_request | The API access is not assigned to a user — assign a user to it in the Offisy settings |
| 401 | invalid_client | Invalid or missing access token |
| 403 | insufficient_scope | Scope reports missing |
| 403 | access_denied | The owning user of your API access lacks the Report Benutzer permission |
| 403 | access_denied | Tenancies add-on is active, but no tenancy is accessible to the owning user of your API access (error_description: No tenancy is accessible to this user.) |
| 404 | not_found | treatingUserId does not reference an existing record |