Availability and leave
Build unavailable timeline intervals for users
/a/Availability_timeline
Build unavailable timeline intervals for users
When to use this endpoint
Render unavailable background overlays for the Availability timeline or Job timeline. Available periods are deliberately omitted rather than represented as positive tiles.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Uses the authenticated tenant’s data. This scheduler/job helper has no extra Availability-management page or role-permission check.
There is no per-user/department visibility or active-user permission filter in this CRM read. Existing target memberships come from the tenant users table; do not pass outsourced-user tokens as local IDs.
Unlike management routes, disabled HR enhancements do not return a feature error here. The helper applies the endpoint-specific empty/available fallback described below after validating request formats and the window.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_ids | Native array or JSON array text | No | Defaults to an empty array, which returns an empty result. A scalar string is JSON-decoded and must become an array. Pass actual positive tenant user IDs; element values are integer-converted, without a public existence/positivity validation error. |
start_e / end_e | Unix seconds | Yes | Integer-converted positive start and strictly later end. Epoch milliseconds are not converted automatically. |
from / to | Unix seconds | Aliases | Used only when start_e/end_e are null or omitted, respectively. A present blank/zero primary field takes precedence and fails validation; a null primary value allows its alias. |
Example request
$result = FM_api('Availability_timeline', [
'user_ids' => json_encode([71]),
'start_e' => '1793005200',
'end_e' => '1793034000',
]);
Example response
{
"71": [
{
"user_id": 71,
"start_e": 1793005200,
"end_e": 1793034000,
"id": 1042,
"event_id": 1042,
"event_type": "annual_leave",
"name": "Annual leave",
"title": "Annual leave",
"source": "availability_event"
}
]
}
Returns a map keyed by requested integer user ID, each value an array of unavailable tiles. Tiles contain user_id, start_e, end_e, id, event_id, event_type, name, title and source. They are not full normalized event objects and do not expose status, notes, requester, approval or specificity.
Real events use source from event.source, then meta.source, then "availability_event". Synthetic outside-shift tiles have event_id/id=0, event_type/source="work_shift" and name/title="Outside work shift". A blank real-event label falls back to the capitalized event-type words.
An optional timeline_style object contains normalized mode/colour from availability-timeline-styles for the event type. Valid modes are tint/stripe/border/solid and colour is a six-digit hex value. The current settings allowlist does not retain work_shift styling. Users with no unavailable segment return empty arrays; disabled HR or empty input returns [].
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"missing or invalid parameter: user_ids"} | A non-array input does not JSON-decode to an array. |
{"error":"missing or invalid time window"} | Integer-converted start is below one or end is not later than start. These request checks run before the disabled-HR fallback. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Only approved (status=1), deleted=0 events overlapping the window are considered: start_e < requested end and end_e > requested start. Company target 0 affects every resolved user, then matching role and any department, then user-specific targets. Precedence is descending specificity (user 4, department 3, role 2, company 1), then cdate, then last_edited, then event ID, all descending. This is creation-time-first within a specificity level, not simply latest edit wins.
- Builds boundaries from the requested window, overlapping events and concrete shift start/end times, then evaluates precedence separately for each segment. A winning available event removes that segment even outside ordinary shifts; otherwise unavailability comes from the event or a synthetic shift gap. Endpoints are clipped to the requested window.
- Adjacent tiles merge only when event ID, type, name, source and normalized style match. Different event identities are not collapsed just because they are both unavailable. Tiles are produced in ascending segment order for each user.
- Integer-normalizes/deduplicates user IDs and drops zeros, but does not validate user existence; a missing user can still produce default-shift gap tiles. Use real positive tenant users.
- There is no server-side duration/page cap; shift generation walks calendar dates in the account timezone. This is a read only: no event/history/balance/notification writes are performed.
See it in Fieldmotion
CRM1
No direct CRM1 caller for Availability_timeline was found in the source search. The implemented management screen is CRM2’s Availability page.
CRM2
In Availability, open the Timeline dialog and change dates/users/department/role/type filters. The dialog sends the visible user IDs to Availability_timeline. The shared Job timeline widget also calls this route for local user rows and overlays only unavailable intervals; filter the Network panel for the exact function.
Related endpoints
Availability_effective: continuous-window result with a representative blocking event.Availability_forScheduler: unclipped real-event inputs instead of tiles.Availability_getDataTable: manage the underlying event rows.