Add a layer
Adds a rotation layer. A layer runs its people in turn, handing over every
day, week or handoff_day days (custom) from rotation_start (default:
now). Handovers fall on calendar days at handoff_time — or, without one,
at the time of day rotation_start falls — on the schedule's clock, so a
rota keeps its local handover time through daylight-saving changes. A
handover time the clocks skip happens when they jump; one they pass twice
happens the first time. Restrict it to a shift — certain weekdays and a time window in the
schedule's timezone — with the three restrict_* fields; a window may cross
midnight. Leave them out for a layer that covers all day, every day.
A schedule that belongs to a team is visible only to callers in that team (and to administrators acting in person); others get 404, as if it did not exist.
Permission (API-key scope): oncall:schedule:write.
Authorization
bearerAuth(oncall:schedule:write)apiKeyHeader(oncall:schedule:write)
Parameters
Path parameters
idstring requiredThe schedule's id.
Request body required
On create name and rotation_type are required.
namestringpriorityintegerrotation_typeRotationTyperotation_startstring (date-time)RFC 3339. Defaults to now on create.handoff_dayintegerFor acustomrotation, the days (1–365) or, withrotation_unithour, the hours (1–168) each turn lasts.rotation_unitstringWhathandoff_daycounts on acustomrotation;daywhen left out.handoff_weekdayintegerThe weekday aweeklyrotation hands over on, 0 (Sunday) to 6.handoff_timestringHH:MM, 00:00–23:59, on the schedule's clock.restrict_to_weekdaysarray of integer0 is Sunday.restrict_start_timestringHH:MM; give the end too. Empty clears the window.restrict_end_timestringHH:MM; may be earlier than the start for a shift across midnight.
Responses
201
The layer.
dataScheduleLayer requiredShow ScheduleLayer properties
idstringschedule_idstringnamestringpriorityintegerLower numbers win. When several layers have someone on call, the layer with the smallestprioritydecides who is paged.rotation_typeRotationTyperotation_startstring (date-time)When the rota's first turn started.handoff_dayintegerFor acustomrotation, the days (or, withrotation_unithour, the hours) each turn lasts. Daily and weekly rotations ignore it.handoff_timestringHH:MMof the handover.rotation_unitstringWhathandoff_daycounts on acustomrotation,dayorhour; empty meansday.handoff_weekdayinteger | nullThe weekday aweeklyrotation hands over on, 0 (Sunday) to 6;nullis the weekdayrotation_startfalls on.restrict_to_weekdaysarray of integerrestrict_start_timestringHH:MMrestrict_end_timestringHH:MMrotationsarray of ScheduleRotationShow ScheduleRotation properties
idstringlayer_idstringuser_idstringpositioninteger0-based place in the rota.created_atstring (date-time)
active_fromstring (date-time)Set on a layer that replaces another from a later moment; it applies from then.active_untilstring (date-time)Set on a layer that a change replaces from a later moment; it applies until then.replaces_layer_idstringOn a changed copy, the layer it replaces.created_atstring (date-time)updated_atstring (date-time)
successboolean required
400
The body is not JSON (INVALID_BODY); name or rotation_type is missing, rotation_type is not daily, weekly or custom, handoff_time is not HH:MM, rotation_start is not RFC 3339, handoff_day is negative (or, on a custom rotation, outside 1–365 days or 1–168 hours), rotation_unit is not day or hour, handoff_weekday or a weekday is outside 0–6, or the shift window is incomplete or malformed (VALIDATION_FAILED, one detail per field).
errorobject requiredcodestring requiredmessagestring requiredrequest_idstringThe request'sX-Request-ID. Quote it to support.detailsarray of object requiredfieldstringmessagestring
401
No API key was sent, or it is unknown, revoked or expired (UNAUTHORIZED).
errorobject requiredcodestring requiredMachine-readable code. Branch on this.messagestring requiredHuman-readable explanation.request_idstringThe request'sX-Request-ID. Quote it to support.
403
The key lacks the scope this endpoint needs (FORBIDDEN).
errorobject requiredcodestring requiredMachine-readable code. Branch on this.messagestring requiredHuman-readable explanation.request_idstringThe request'sX-Request-ID. Quote it to support.
404
No schedule with this id in your organization (NOT_FOUND).
errorobject requiredcodestring requiredMachine-readable code. Branch on this.messagestring requiredHuman-readable explanation.request_idstringThe request'sX-Request-ID. Quote it to support.
429
Too many requests (RATE_LIMITED). Wait Retry-After seconds.
Retry-AfterintegerSeconds to wait.
errorobject requiredcodestring requiredMachine-readable code. Branch on this.messagestring requiredHuman-readable explanation.request_idstringThe request'sX-Request-ID. Quote it to support.
500
Something went wrong on EvoHub's side (INTERNAL_ERROR). Retry later.
errorobject requiredcodestring requiredMachine-readable code. Branch on this.messagestring requiredHuman-readable explanation.request_idstringThe request'sX-Request-ID. Quote it to support.
Example request
curl -X POST 'https://evohub.io/api/v1/schedules/5b1c7d2e-8f3a-4b9c-a0d1-e2f3a4b5c6d7/layers' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"name": "Business hours",
"handoff_day": 1,
"handoff_time": "09:00",
"rotation_type": "weekly",
"rotation_start": "2026-09-01T06:00:00Z",
"restrict_end_time": "18:00",
"restrict_start_time": "09:00",
"restrict_to_weekdays": [
1,
2,
3,
4,
5
]
}'
