ReferenceReference by module

Availability API

Every Availability action (13) and data model (7): endpoints, scopes, input, preconditions, events and examples.

Opening hours, special days, time off and who offers which service.

Module code availability · 13 actions · 7 data models · 12 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: availability (everything), availability:read (read only) or availability:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
leave_allowancesleave_allowance/api/v1/leave_allowances
leave_periodsleave_period/api/v1/leave_periods
leave_typesleave_type/api/v1/leave_types
service_available_daysservice_available_day/api/v1/service_available_days
service_providersservice_provider/api/v1/service_providers
working_hour_overridesworking_hour_override/api/v1/working_hour_overrides
working_hoursworking_hour/api/v1/working_hours

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
availability.adjust_allowanceavailability:manageAdjust a balance
availability.approve_leaveavailability:writeApprove time off
availability.cancel_leaveavailability:writeWithdraw time off
availability.carry_overavailability:manageClose a leave year
availability.clear_overrideavailability:manageRemove a special day
availability.clear_person_hoursavailability:manageUse the workspace hours
availability.reject_leaveavailability:writeDecline time off
availability.request_leaveavailability:writeRequest time off
availability.save_leave_typeavailability:manageSave a kind of time off
availability.set_hoursavailability:manageSet opening hours
availability.set_item_daysavailability:manageSet which days something runs
availability.set_item_providersavailability:manageSet who can do it
availability.set_overrideavailability:manageSet a special day

availability.adjust_allowance

Adjust a balance — Adds or removes days on one person’s balance for one year — a joiner’s pro-rata, a correction.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/leave_allowances/actions/adjust_allowance
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.adjust_allowance

Input

FieldTypeRequiredNotes
userIduuidyesTeam member · id of app_user
leaveTypestringyesKind · max 40
yearnumberyesYear · min 2000 · max 2100
adjustmentnumberyesAdjustment (days) · min -366 · max 366
notestringWhy · max 1000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_leave_typeOnly a counted kind has a balance.
not_a_memberThey must be a member of this workspace.

Events it publishes: availability.allowance_adjusted

What it writes: leave_allowance (upsert) — Sets the adjustment for that year

curl -X POST https://app.getera.io/api/v1/leave_allowances/actions/adjust_allowance \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"userId":"APP_USER_ID","leaveType":"Kind","year":2000,"adjustment":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.allowance_adjusted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leaveAllowances.adjustAllowance({
  userId: "APP_USER_ID",
  leaveType: "Kind",
  year: 2000,
  adjustment: 1
})
era leave_allowances adjust_allowance \
  --user-id "APP_USER_ID" \
  --leave-type "Kind" \
  --year 2000 \
  --adjustment 1
tools/call
{
  "name": "era__availability__adjust_allowance",
  "arguments": {
    "userId": "APP_USER_ID",
    "leaveType": "Kind",
    "year": 2000,
    "adjustment": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_leave_type, not_a_member · 429 slow down

availability.approve_leave

Approve time off — Makes time off real, naming any appointments it would break.

Needs availability:write · changes data

POSThttps://app.getera.io/api/v1/leave_periods/{id}/actions/approve_leave
API key or OAuth token · availability:write
  • Canonical address: POST /api/v1/actions/availability.approve_leave

Input

FieldTypeRequiredNotes
leaveIduuidyesFilled from the path {id} · Request · id of leave_period
forcebooleanApprove anyway
notestringNote · max 1000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
already_approvedIt must not already be approved.
not_foundThe request must exist.
not_pendingOnly a request still waiting can be decided.
cannot_approve_ownYour own time off is decided by somebody else, unless you hold Configure.
not_an_approverTheir manager, or somebody who can approve, decides.
clashes_with_appointmentsAppointments inside the time off are named.

Events it publishes: availability.leave_approved

What it writes: leave_period (update) — Marks it approved

curl -X POST https://app.getera.io/api/v1/leave_periods/LEAVE_PERIOD_ID/actions/approve_leave \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"force":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_approved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leavePeriods.approveLeave("LEAVE_PERIOD_ID", {
  force: true
})
era leave_periods approve_leave LEAVE_PERIOD_ID \
  --force true
tools/call
{
  "name": "era__availability__approve_leave",
  "arguments": {
    "leaveId": "LEAVE_PERIOD_ID",
    "force": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 already_approved, not_found, not_pending, cannot_approve_own, not_an_approver, clashes_with_appointments · 429 slow down

availability.cancel_leave

Withdraw time off — Withdraws a request, or gives back approved time off that has not started.

Needs availability:write · removes or cannot be undone

POSThttps://app.getera.io/api/v1/leave_periods/{id}/actions/cancel_leave
API key or OAuth token · availability:write
  • Canonical address: POST /api/v1/actions/availability.cancel_leave

Input

FieldTypeRequiredNotes
leaveIduuidyesFilled from the path {id} · Request · id of leave_period

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe request must exist.
not_your_leaveOnly the person, or somebody with Configure, can withdraw it.
cannot_cancelDeclined, withdrawn or already-started time off cannot be withdrawn.

Events it publishes: availability.leave_cancelled

What it writes: leave_period (update) — Marks it withdrawn

curl -X POST https://app.getera.io/api/v1/leave_periods/LEAVE_PERIOD_ID/actions/cancel_leave \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_cancelled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leavePeriods.cancelLeave("LEAVE_PERIOD_ID")
era leave_periods cancel_leave LEAVE_PERIOD_ID
tools/call
{
  "name": "era__availability__cancel_leave",
  "arguments": {
    "leaveId": "LEAVE_PERIOD_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_your_leave, cannot_cancel · 429 slow down

availability.carry_over

Close a leave year — Moves what is left of each balance into the next year, up to each kind’s carry-over limit.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/leave_allowances/actions/carry_over
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.carry_over

Input

FieldTypeRequiredNotes
yearnumberyesYear · min 2000 · max 2100

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
year_not_overOnly a year that has ended can be closed.

Events it publishes: availability.leave_carried_over

What it writes: leave_allowance (upsert) — Writes next year’s carried-over days

curl -X POST https://app.getera.io/api/v1/leave_allowances/actions/carry_over \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"year":2000}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_carried_over"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leaveAllowances.carryOver({
  year: 2000
})
era leave_allowances carry_over \
  --year 2000
tools/call
{
  "name": "era__availability__carry_over",
  "arguments": {
    "year": 2000
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 year_not_over · 429 slow down

availability.clear_override

Remove a special day — Puts one date back on the weekly hours.

Needs availability:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/working_hour_overrides/{id}/actions/clear_override
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.clear_override

Input

FieldTypeRequiredNotes
overrideIduuidyesFilled from the path {id} · Special day · id of working_hour_override

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe special day must still exist.

Events it publishes: availability.override_cleared

What it writes: working_hour_override (delete) — Removes that date’s exception

curl -X POST https://app.getera.io/api/v1/working_hour_overrides/WORKING_HOUR_OVERRIDE_ID/actions/clear_override \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.override_cleared"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workingHourOverrides.clearOverride("WORKING_HOUR_OVERRIDE_ID")
era working_hour_overrides clear_override WORKING_HOUR_OVERRIDE_ID
tools/call
{
  "name": "era__availability__clear_override",
  "arguments": {
    "overrideId": "WORKING_HOUR_OVERRIDE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

availability.clear_person_hours

Use the workspace hours — Removes one person’s own working week, so the workspace’s opening hours apply to them again.

Needs availability:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/working_hours/actions/clear_person_hours
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.clear_person_hours

Input

FieldTypeRequiredNotes
userIduuidyesTeam member

Events it publishes: availability.hours_changed

What it writes: working_hour (delete) — Removes that person’s weekday rows

curl -X POST https://app.getera.io/api/v1/working_hours/actions/clear_person_hours \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"userId":"USER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.hours_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workingHours.clearPersonHours({
  userId: "USER_ID"
})
era working_hours clear_person_hours \
  --user-id "USER_ID"
tools/call
{
  "name": "era__availability__clear_person_hours",
  "arguments": {
    "userId": "USER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down

availability.reject_leave

Decline time off — Declines a request, with a reason the requester is told.

Needs availability:write · changes data

POSThttps://app.getera.io/api/v1/leave_periods/{id}/actions/reject_leave
API key or OAuth token · availability:write
  • Canonical address: POST /api/v1/actions/availability.reject_leave

Input

FieldTypeRequiredNotes
leaveIduuidyesFilled from the path {id} · Request · id of leave_period
notestringReason · max 1000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe request must exist.
not_pendingOnly a request still waiting can be decided.
cannot_approve_ownYour own time off is decided by somebody else, unless you hold Configure.
not_an_approverTheir manager, or somebody who can approve, decides.

Events it publishes: availability.leave_rejected

What it writes: leave_period (update) — Marks it declined

curl -X POST https://app.getera.io/api/v1/leave_periods/LEAVE_PERIOD_ID/actions/reject_leave \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"note":"Reason"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_rejected"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leavePeriods.rejectLeave("LEAVE_PERIOD_ID", {
  note: "Reason"
})
era leave_periods reject_leave LEAVE_PERIOD_ID \
  --note "Reason"
tools/call
{
  "name": "era__availability__reject_leave",
  "arguments": {
    "leaveId": "LEAVE_PERIOD_ID",
    "note": "Reason"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_pending, cannot_approve_own, not_an_approver · 429 slow down

availability.request_leave

Request time off — Records time off, counts its working days against the balance, and blocks nothing until it is approved.

Needs availability:write · changes data

POSThttps://app.getera.io/api/v1/leave_periods/actions/request_leave
API key or OAuth token · availability:write
  • Canonical address: POST /api/v1/actions/availability.request_leave

Input

FieldTypeRequiredNotes
userIduuidTeam member · Leave empty for time off that closes the whole organisation.
titlestringyesTitle · max 120
leaveTypestringKind · max 40
startDatedateyesFrom
endDatedateyesTo
isAllDaybooleanAll day
startTimestringFrom (time) · max 8
endTimestringTo (time) · max 8
descriptionstringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_rangeThe end must not be before the start, and one request covers at most a year.
times_requiredA part-day leave needs both times.
not_your_leaveSomebody else’s time off, or the whole organisation’s, needs Configure.
unknown_leave_typeThe kind must be one this workspace uses.
overlaps_existingIt must not overlap time off already requested or approved.
insufficient_balanceA counted kind cannot go below zero unless its policy allows it.

Events it publishes: availability.leave_requested

What it writes: leave_period (insert) — Records the request

curl -X POST https://app.getera.io/api/v1/leave_periods/actions/request_leave \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"title":"Title","startDate":"2026-11-02","endDate":"2026-11-02"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_requested"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leavePeriods.requestLeave({
  title: "Title",
  startDate: "2026-11-02",
  endDate: "2026-11-02"
})
era leave_periods request_leave \
  --title "Title" \
  --start-date "2026-11-02" \
  --end-date "2026-11-02"
tools/call
{
  "name": "era__availability__request_leave",
  "arguments": {
    "title": "Title",
    "startDate": "2026-11-02",
    "endDate": "2026-11-02"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_range, times_required, not_your_leave, unknown_leave_type, overlaps_existing, insufficient_balance · 429 slow down

availability.save_leave_type

Save a kind of time off — Adds or changes a kind of time off and its policy: accrual, carry-over and ceiling.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/leave_types/actions/save_leave_type
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.save_leave_type

Input

FieldTypeRequiredNotes
codestringyesCode · max 40
labelstringyesName · max 80
colourstringColour · max 20
isPaidbooleanPaid
accrualPeriodstring (enum)Accrues · Allowed values: none, year, month
accrualDaysnumberDays per period · max 366
carryOverMaxnumberCarry over at most · max 366
maxBalancenumberBalance ceiling · max 999
allowNegativebooleanMay go below zero
isActivebooleanIn use

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_codeA code is lower-case letters, digits and underscores.
invalid_policyA counted kind accrues something, and carry-over fits under the ceiling.

Events it publishes: availability.leave_type_saved

What it writes: leave_type (upsert) — Writes the kind and its policy

curl -X POST https://app.getera.io/api/v1/leave_types/actions/save_leave_type \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"code":"Code","label":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.leave_type_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leaveTypes.saveLeaveType({
  code: "Code",
  label: "Name"
})
era leave_types save_leave_type \
  --code "Code" \
  --label "Name"
tools/call
{
  "name": "era__availability__save_leave_type",
  "arguments": {
    "code": "Code",
    "label": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_code, invalid_policy · 429 slow down

availability.set_hours

Set opening hours — Changes one weekday — one or more opening blocks — naming any appointments it would put outside the hours.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/working_hours/actions/set_hours
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.set_hours

Input

FieldTypeRequiredNotes
userIduuidTeam member · Leave empty to set the whole workspace’s hours.
weekdaynumberyesWeekday · min 0 · max 6
isWorkingDaybooleanOpen that day
startsAtstringOpens · max 8
endsAtstringCloses · max 8
blocksobject / arrayOpening blocks · Several blocks in one day, e.g. [{"startsAt":"09:00","endsAt":"12:30"},{"startsAt":"13:30","endsAt":"18:00"}]. Replaces Opens/Closes.
forcebooleanChange anyway

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
hours_requiredAn open day needs both times.
invalid_rangeClosing must be after opening.
overlapping_blocksOpening blocks in one day may not overlap.
orphans_appointmentsAppointments left outside the new hours are named.

Events it publishes: availability.hours_changed

What it writes: working_hour (upsert) — Replaces that weekday’s hours

curl -X POST https://app.getera.io/api/v1/working_hours/actions/set_hours \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"weekday":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.hours_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workingHours.setHours({
  weekday: 1
})
era working_hours set_hours \
  --weekday 1
tools/call
{
  "name": "era__availability__set_hours",
  "arguments": {
    "weekday": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 hours_required, invalid_range, overlapping_blocks, orphans_appointments · 429 slow down

availability.set_item_days

Set which days something runs — Restricts a catalogue entry to certain weekdays. Empty means every day.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/service_available_days/actions/set_item_days
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.set_item_days

Input

FieldTypeRequiredNotes
itemIduuidyesItem · id of item
daysstringWeekdays · Comma-separated, 0 = Sunday. Leave empty for every day. · max 32

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe catalogue entry must exist.
invalid_weekdayA weekday must be between 0 and 6.

Events it publishes: availability.item_days_changed

What it writes: service_available_day (upsert) — Replaces the weekday restriction

curl -X POST https://app.getera.io/api/v1/service_available_days/actions/set_item_days \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemId":"ITEM_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.item_days_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.serviceAvailableDays.setItemDays({
  itemId: "ITEM_ID"
})
era service_available_days set_item_days \
  --item-id "ITEM_ID"
tools/call
{
  "name": "era__availability__set_item_days",
  "arguments": {
    "itemId": "ITEM_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, invalid_weekday · 429 slow down

availability.set_item_providers

Set who can do it — Replaces the team members who can perform one catalogue entry.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/service_providers/actions/set_item_providers
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.set_item_providers

Input

FieldTypeRequiredNotes
itemIduuidyesItem · id of item
userIdsstringTeam members · Comma-separated user ids. Leave empty to assign nobody. · max 2000
forcebooleanAssign anyway

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe catalogue entry must exist.
not_a_memberEveryone assigned must be an active member here.
clashes_with_appointmentsBookings that still name someone being removed are listed.

Events it publishes: availability.item_providers_changed

What it writes: service_provider (upsert) — Replaces the assignment list

curl -X POST https://app.getera.io/api/v1/service_providers/actions/set_item_providers \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemId":"ITEM_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.item_providers_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.serviceProviders.setItemProviders({
  itemId: "ITEM_ID"
})
era service_providers set_item_providers \
  --item-id "ITEM_ID"
tools/call
{
  "name": "era__availability__set_item_providers",
  "arguments": {
    "itemId": "ITEM_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_a_member, clashes_with_appointments · 429 slow down

availability.set_override

Set a special day — Overrides the weekly hours for one date — a holiday, or a one-off opening.

Needs availability:manage · changes data

POSThttps://app.getera.io/api/v1/working_hour_overrides/actions/set_override
API key or OAuth token · availability:manage
  • Canonical address: POST /api/v1/actions/availability.set_override

Input

FieldTypeRequiredNotes
overrideDatedateyesDate
titlestringyesWhy · max 120
userIduuidTeam member · Leave empty for the whole workspace.
isWorkingDaybooleanOpen that day
startsAtstringOpens · max 8
endsAtstringCloses · max 8
forcebooleanSet anyway

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
hours_requiredAn open day needs both times.
invalid_rangeClosing must be after opening.
clashes_with_appointmentsAppointments already booked that day are named.

Events it publishes: availability.override_set

What it writes: working_hour_override (upsert) — Replaces that date’s exception

curl -X POST https://app.getera.io/api/v1/working_hour_overrides/actions/set_override \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"overrideDate":"2026-11-02","title":"Why"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "availability.override_set"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workingHourOverrides.setOverride({
  overrideDate: "2026-11-02",
  title: "Why"
})
era working_hour_overrides set_override \
  --override-date "2026-11-02" \
  --title "Why"
tools/call
{
  "name": "era__availability__set_override",
  "arguments": {
    "overrideDate": "2026-11-02",
    "title": "Why"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold availability:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 hours_required, invalid_range, clashes_with_appointments · 429 slow down

Data models

LeaveAllowance

Table leave_allowance · Resource leave_allowances

  • GET /api/v1/leave_allowances
  • GET /api/v1/leave_allowances/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
leave_type_codestring · text
yearinteger · int4
carried_overstring (decimal) · numeric
adjustmentstring (decimal) · numeric
notestring · textyes
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, user_id, leave_type_code, year

Checks:

  • CHECK ((carried_over >= (0)::numeric))
  • CHECK (((year >= 2000) AND (year <= 2100)))

LeavePeriod

Table leave_period · Resource leave_periods

  • GET /api/v1/leave_periods
  • GET /api/v1/leave_periods/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidyesapp_user
leave_typestring · text
titlestring · text
descriptionstring · textyes
start_datestring (date) · date
end_datestring (date) · date
is_all_dayboolean · bool
start_timestring (time) · timeyes
end_timestring (time) · timeyes
statusstring · textrequested, approved, rejected, cancelled
created_atstring (date-time) · timestamptz
daysstring (decimal) · numericyes
requested_by_user_idstring (uuid) · uuidyesapp_user
decided_by_user_idstring (uuid) · uuidyesapp_user
decided_atstring (date-time) · timestamptzyes
decision_notestring · textyes

Primary key: id

Checks:

  • CHECK ((end_date >= start_date))
  • CHECK ((is_all_day OR ((start_time IS NOT NULL) AND (end_time IS NOT NULL) AND (end_time > start_time))))

LeaveType

Table leave_type · Resource leave_types

  • GET /api/v1/leave_types
  • GET /api/v1/leave_types/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
codestring · text
labelstring · text
colourstring · text
is_paidboolean · bool
accrual_periodstring · textnone, year, month
accrual_daysstring (decimal) · numeric
carry_over_maxstring (decimal) · numeric
max_balancestring (decimal) · numericyes
allow_negativeboolean · bool
is_activeboolean · bool
sort_orderinteger · int4
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, code

Checks:

  • CHECK ((accrual_days >= (0)::numeric))
  • CHECK ((carry_over_max >= (0)::numeric))
  • CHECK ((code ~ '^[a-z][a-z0-9_]{0,39}$'::text))
  • CHECK ((length(TRIM(BOTH FROM label)) > 0))
  • CHECK (((max_balance IS NULL) OR (max_balance > (0)::numeric)))

ServiceAvailableDay

Table service_available_day · Resource service_available_days

  • GET /api/v1/service_available_days
  • GET /api/v1/service_available_days/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
day_of_weekinteger · int2

Primary key: id

Unique: item_id, day_of_week

Checks:

  • CHECK (((day_of_week >= 0) AND (day_of_week <= 6)))

ServiceProvider

Table service_provider · Resource service_providers

  • GET /api/v1/service_providers
  • GET /api/v1/service_providers/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
user_idstring (uuid) · uuidapp_user

Primary key: id

Unique: item_id, user_id

WorkingHourOverride

Table working_hour_override · Resource working_hour_overrides

  • GET /api/v1/working_hour_overrides
  • GET /api/v1/working_hour_overrides/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidyesapp_user
override_datestring (date) · date
titlestring · text
is_working_dayboolean · bool
starts_atstring (time) · timeyes
ends_atstring (time) · timeyes
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((is_working_day AND (starts_at IS NOT NULL) AND (ends_at IS NOT NULL) AND (ends_at > starts_at)) OR (NOT is_working_day)))
  • CHECK ((override_date IS NOT NULL))

WorkingHour

Table working_hour · Resource working_hours

  • GET /api/v1/working_hours
  • GET /api/v1/working_hours/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidyesapp_user
weekdayinteger · int2
is_working_dayboolean · bool
starts_atstring (time) · timeyes
ends_atstring (time) · timeyes

Primary key: id

Unique: workspace_id, user_id, weekday, starts_at

Checks:

  • CHECK (((is_working_day AND (starts_at IS NOT NULL) AND (ends_at IS NOT NULL) AND (ends_at > starts_at)) OR (NOT is_working_day)))
  • CHECK (((weekday >= 0) AND (weekday <= 6)))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
availability.allowance_adjustedSomebody’s leave balance was adjusted by hand.id, userId, leaveType, year, adjustment, recipientUserId
availability.hours_changedOpening hours were changed.weekday
availability.item_days_changedThe weekdays a catalogue entry runs on changed.id, days
availability.item_providers_changedWho can perform a catalogue entry changed.id, userIds
availability.leave_approvedTime off was approved and now blocks bookings.id, userId, clashes, recipientUserId
availability.leave_cancelledTime off was withdrawn.id, userId, recipientUserId
availability.leave_carried_overA leave year was closed and unused days carried over.year, balances, moved
availability.leave_rejectedA time-off request was declined.id, userId, note, recipientUserId
availability.leave_requestedSomeone requested time off. Addressed to their manager.id, userId, leaveType, startDate, endDate, days, recipientUserId
availability.leave_type_savedA kind of time off or its policy changed.id, code
availability.override_clearedA date went back to the weekly hours.id, overrideDate
availability.override_setA single date was given its own hours.id, overrideDate, isWorkingDay
Was this page helpful?