REST API Calendar - edmozley/freeitsm GitHub Wiki

๐Ÿ—“๏ธ REST API: Calendar

The complete usage guide for the standalone Calendar module of the REST API โ€” the shared team calendar's events and categories. Mirrors the interactive documentation at System โ†’ API โ†’ Documentation (with its live "Try it" tester).

[!NOTE] New to the API? The basics table on REST API: Tickets covers base URL, authentication, the response envelope, error codes, rate limits and PATCH semantics โ€” identical across all modules. Except one thing here โ€” read the datetime warning below.

What's distinctive about Calendar:

๐Ÿ• Naive server-local datetimes Unlike every other module (ISO 8601 UTC with Z), calendar events are stored without timezone conversion โ€” that's how the UI writes them and how the ICS feed interprets them. This resource accepts and returns naive YYYY-MM-DD HH:MM:SS values and rejects Z/offset designators with a 422, so you can't accidentally shift every meeting by an hour.
๐Ÿค– Generated events are read-only Rows with source = "asset_warranty" are owned by the warranty sync, which wipes and regenerates them wholesale. The API shows you source on reads (the internal endpoints don't return it at all!) and answers 409 to updates/deletes on generated rows โ€” tighter than the UI, where an edit silently evaporates on the next sync. You can never set source on create.
๐Ÿ“ก The ICS feed already exists For subscribing Outlook/Google/Apple Calendar, use the built-in token-authenticated feed (api/calendar/feed.php?token=โ€ฆ, issued per-analyst from the Calendar UI). The REST API is for programmatic event management โ€” creating maintenance windows from a pipeline, syncing from another system.
๐ŸŒ One shared calendar Install-wide, no per-analyst or per-company calendars โ€” matching the module.

๐Ÿš€ Quick start

A deployment pipeline booking its maintenance window:

B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โ€ฆ"

curl -X POST "$B/calendar/events" -H "$K" -H "Content-Type: application/json" -d '{
  "title": "Maintenance window โ€” release 2.4",
  "start_at": "2026-07-05 06:00:00",
  "end_at":   "2026-07-05 08:00:00",
  "category_id": 1,
  "location": "Production",
  "description": "Core switch SFP replacement (CHG-0011)."
}'

๐Ÿ—“๏ธ Events

๐ŸŸข GET /calendar/events โ€” list in a window ย  ๐Ÿ”‘ calendar_events.read

Provide a from/to window (the UI's exact three-branch overlap logic โ€” an event matches if it starts in, ends in, or spans the window; from inclusive, to exclusive) โ€” or contract_id, or all=true.

Parameter Description
from / to Naive local datetimes โ€” 2026-07-01 00:00:00 (T separator OK, date-only OK)
contract_id Events linked to a contract (window optional)
all true = everything (paginate!)
category_id One category โ€” or categories=1,2,3 for several
source manual (source is null) or a generator name like asset_warranty
q Search title and location
page / per_page Pagination โ€” default 1 / 25, max 100

The event shape:

{ "id": 12, "title": "Maintenance window โ€” release 2.4",
  "description": "Core switch SFP replacement (CHG-0011).",
  "category": { "id": 1, "name": "Maintenance", "color": "#ef6c00" },
  "start_at": "2026-07-05 06:00:00", "end_at": "2026-07-05 08:00:00",
  "all_day": false, "location": "Production",
  "contract_id": null,
  "source": null,
  "created_by": { "id": 1, "name": "Administrator" },
  "created_at": "2026-07-03 16:56:41", "updated_at": "2026-07-03 16:56:41" }

source: null = a manual event you can edit. source: "asset_warranty" = generated (read-only; created_by is null โ€” the sync's sentinel).

๐Ÿ”ต POST /calendar/events โ€” create ย  ๐Ÿ”‘ calendar_events.create

Field Required Description
title โœ… Event title
start_at โœ… Naive local datetime
end_at Defaults to start_at; can't be before it (422)
all_day Boolean
description / location Details
category_id Validated (422 on unknown โ€” friendlier than the UI's raw FK error)
contract_id Link to a contract (validated)

Always creates a manual event (source can never be set). Returns 201.

๐ŸŸข GET /calendar/events/{id} ย  ๐Ÿ”‘ calendar_events.read ยท ๐ŸŸ  PATCH /calendar/events/{id} ย  ๐Ÿ”‘ calendar_events.update

Everything creatable is patchable; title and start_at can't be cleared.

[!WARNING] A generated event (source set) answers 409 to PATCH โ€” "generated by the 'asset_warranty' sync and read-only โ€” it would be recreated on the next sync anyway."

๐Ÿ”ด DELETE /calendar/events/{id} ย  ๐Ÿ”‘ calendar_events.delete

Deletes a manual event. Generated events answer 409 โ€” retire them by clearing the asset's warranty date (or the warranty-surface setting) and letting the sync take them away.


๐ŸŽจ Categories

๐ŸŸข GET /calendar-categories ย  ๐Ÿ”‘ reference.read

All categories with colour and live event counts (category management stays in Calendar โ†’ Settings):

{ "data": [ { "id": 1, "name": "Maintenance", "color": "#ef6c00",
              "description": null, "is_active": true, "event_count": 4 } ] }

๐Ÿงช Worked example: today's ops briefing

A read-only key (calendar_events: read + reference: read) posting the day's schedule to chat:

B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โ€ฆ"
TODAY=$(date +%F)

curl -s -H "$K" "$B/calendar/events?from=$TODAY%2000:00:00&to=$TODAY%2023:59:59&per_page=50" \
  | jq -r '.data[] | "\(.start_at[11:16])  [\(.category.name // "-")]  \(.title)\(if .source then " ๐Ÿค–" else "" end)"'

And the automation direction โ€” clearing a cancelled maintenance window by title:

ID=$(curl -s -H "$K" "$B/calendar/events?all=true&q=release+2.4" | jq -r '.data[0].id')
curl -s -X DELETE "$B/calendar/events/$ID" -H "$K"

Under the hood: REST API โ€” How It Works ยท Other modules: Tickets ยท Assets ยท Problems ยท Changes ยท Knowledge ยท Tasks ยท CMDB ยท Contracts ยท Keys & permissions: System โ†’ API (System module) ยท Module docs: Calendar.