Calendar Events
Reference for the calendar_events resource. Requests follow the conventions in
Requests and Responses; fields you
receive and may write are filtered by your user's permissions, so responses can
contain a subset of the fields below.
Operations
| Operation | Request |
|---|---|
| List | GET /{profile}/user/v4/calendar_events |
| Schedule a tech or sales appointment for a customer | POST /{profile}/user/v4/calendar_events/schedule |
| Reschedule an appointment (new start time, optional audit record) | POST /{profile}/user/v4/calendar_events/reschedule |
| Cancel (delete) an appointment | POST /{profile}/user/v4/calendar_events/cancel |
Not available as a standard REST operation for this resource: create, update, delete —
such requests return 402 feature_not_enabled or 403 permission_denied (see the actions above for this resource's write path).
How it works
calendar_events are appointments — one table holding both tech appointments
(calendar_category: tech_schedule: installs, service visits, removals) and sales appointments
(calendar_category: sale_schedule). The table has a composite key (id, calendar_category), so
records are not addressed at /{id}; instead, appointments of both kinds are managed through three
collection actions — schedule, reschedule, and cancel — that take the appointment
id (or, for schedule, the calendar_category) in the body.
Permissions follow the SecurityTrax scheduler:
- Tech appointments need the Scheduler permission at the customer's location (create / modify / delete for schedule / reschedule / cancel). Your own appointments are always visible.
- Sales appointments need the Sale Scheduler permission, or Assign Sale Schedule To Self — in which case you may only schedule appointments assigned to yourself.
Scheduling a tech appointment
curl -X POST "https://portal.securitytrax.com/acme/user/v4/calendar_events/schedule" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"customer_id":1001,"user_id":42,"calendar_event_type_id":1,"customer_note_id":5005,"start_time":1767290400,"duration":7200,"notes":"Bring the replacement panel"}}}'
calendar_category defaults to tech_schedule.
| Field | Required | Notes |
|---|---|---|
customer_id |
Yes | The customer. Leads are rejected for tech appointments — leads use the sales scheduler. |
calendar_event_type_id |
Yes | An active tech service type (install / service / removal as configured by your company). Time Off cannot be scheduled through the API. |
start_time |
Yes | Unix timestamp or a date-time string (e.g. 2026-08-03 10:00:00). |
duration |
Yes | Seconds; must be a multiple of 1800 (30-minute increments) and may not run past 11:30 PM. |
user_id |
No | The tech to assign; the user must hold the tech role. Omit to leave unassigned. |
calendar_event_detail_type_id |
No | Service detail type (must belong to the tech scheduler). |
customer_note_id |
No* | The work order to link — must be a work order belonging to this customer. *Required when the company setting "appointments require a work order" is on. |
notes, user_notes |
No | Appointment notes / notes for the assigned tech. |
Scheduling a sales appointment
Pass calendar_category: sale_schedule:
curl -X POST "https://portal.securitytrax.com/acme/user/v4/calendar_events/schedule" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"calendar_category":"sale_schedule","customer_id":1001,"user_id":42,"calendar_event_type_id":1,"start_time":1767290400,"duration":3600}}}'
| Field | Required | Notes |
|---|---|---|
customer_id |
Yes | A lead always, or a customer when your company shows the sales scheduler on customers. |
calendar_event_type_id |
Yes | An active sale visit type as configured by your company. |
start_time, duration |
Yes | Same rules as tech appointments. |
user_id |
No | The sales rep to assign. With only Assign Sale Schedule To Self, this must be your own user id (and an unassigned appointment is not allowed). |
notes, user_notes |
No | Appointment notes / notes for the assigned rep. |
Sales appointments cannot link a work order (customer_note_id is rejected).
Scheduling through the API runs the same platform side effects as scheduling in SecurityTrax (appointment notifications, remote system sync where configured).
Note. The API performs no double-booking check — like the other integration surfaces, it will happily schedule someone into an occupied window. Check the assignee's existing appointments first (
GET /calendar_events?user_id=42&start_from=...&start_to=...) if overlap matters to your flow.
Rescheduling
curl -X POST "https://portal.securitytrax.com/acme/user/v4/calendar_events/reschedule" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"id":314,"start_time":1767376800,"initiated_by":"c","reschedule_reason_id":2}}}'
Works for both tech and sales appointments (the id resolves the kind). start_time is required (unix
timestamp or date-time string); pass duration only to change the length. initiated_by (c =
customer, d = dealer/company) is optional — when provided and the company tracks reschedules, a
reschedule audit record (old time, new time, reason, who initiated) is written alongside the move,
exactly as the SecurityTrax scheduler does.
Canceling
curl -X POST "https://portal.securitytrax.com/acme/user/v4/calendar_events/cancel" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"id":314}}}'
Deletes the appointment from the schedule. A linked work order is not closed or unlinked — it simply no longer has this appointment.
Listing appointments
Filters: customer_id, user_id (the assigned tech/rep), calendar_category
(tech_schedule / sale_schedule), calendar_event_type_id, customer_note_id (work order), and
a start-time window via start_from / start_to (unix timestamps). Sort by id, customer_id,
user_id, start_time, duration, or created_at (default start_time, newest first);
?count_only=true for the total.
# A tech's appointments for one day
curl "https://portal.securitytrax.com/acme/user/v4/calendar_events?user_id=42&start_from=1767250800&start_to=1767337199" \
-H "Authorization: Bearer stx_acme_..."
Fields
Fields are grouped by the permission that gates them. A group you may not view
is absent from responses; a group you may not write is rejected with 422 when
sent in a write.
Tech Appointment
View: customers — the standard canViewTechSchedule rules; leads — Lead Scheduler. Create: customers — Scheduler at the record's location. Update: customers — Scheduler at the record's location.
| Field | Type | Writable | Validation |
|---|---|---|---|
calendar_category |
string (nullable) | Create only | one of: tech_schedule, sale_schedule |
user_id |
integer (nullable) | Create, update | min 0 |
customer_note_id |
integer (nullable) | Create, update | min 0 |
customer_id |
integer (nullable) | Create only | min 0 |
calendar_event_type_id |
integer (nullable) | Create, update | min 0 |
calendar_event_detail_type_id |
integer (nullable) | Create, update | min 0 |
recurring_id |
integer (nullable) | Create, update | min 0 |
start_time |
string (nullable) | Create, update | min length 0 |
duration |
integer (nullable) | Create, update | min 0 |
notes |
string (nullable) | Create, update | — |
user_notes |
string (nullable) | Create, update | — |
remote_unique_id |
string (nullable) | Create, update | max length 255 |
work_order_number |
string (nullable) | Create, update | max length 255 |
dry_run_reason_id |
integer (nullable) | Create, update | min 0 |
interactive_services_id |
integer (nullable) | Create, update | max 255 |
status |
string (nullable) | Read-only | one of: active, deleted |
created_at |
string (nullable) | Read-only | — |
created_by |
integer (nullable) | Read-only | — |
updated_at |
string (nullable) | Read-only | — |
updated_by |
integer (nullable) | Read-only | — |
Sales Appointment
View: any of: Sale Scheduler; Assign Sale Schedule To Self. Create: any of: Sale Scheduler; Assign Sale Schedule To Self. Update: the standard canModifySaleSchedulerAppointment rules.
| Field | Type | Writable | Validation |
|---|---|---|---|
calendar_category |
string (nullable) | Create only | one of: tech_schedule, sale_schedule |
user_id |
integer (nullable) | Create, update | min 0 |
customer_note_id |
integer (nullable) | Create, update | min 0 |
customer_id |
integer (nullable) | Create only | min 0 |
calendar_event_type_id |
integer (nullable) | Create, update | min 0 |
calendar_event_detail_type_id |
integer (nullable) | Create, update | min 0 |
recurring_id |
integer (nullable) | Create, update | min 0 |
start_time |
string (nullable) | Create, update | min length 0 |
duration |
integer (nullable) | Create, update | min 0 |
notes |
string (nullable) | Create, update | — |
user_notes |
string (nullable) | Create, update | — |
remote_unique_id |
string (nullable) | Create, update | max length 255 |
work_order_number |
string (nullable) | Create, update | max length 255 |
dry_run_reason_id |
integer (nullable) | Create, update | min 0 |
interactive_services_id |
integer (nullable) | Create, update | max 255 |
status |
string (nullable) | Read-only | one of: active, deleted |
created_at |
string (nullable) | Read-only | — |
created_by |
integer (nullable) | Read-only | — |
updated_at |
string (nullable) | Read-only | — |
updated_by |
integer (nullable) | Read-only | — |
Pagination
The list endpoint uses client-controlled offset pagination: ?page= (1-based) and
?per_page= (default 25, max 100). The response mirrors
meta.pagination (page, per_page, total, last_page) and sends an RFC5988
Link header; follow rel="next" to walk pages. See
Pagination.
Filters
The list endpoint accepts these query-param filters: customer_id, user_id, calendar_category, calendar_event_type_id, customer_note_id, start_from, start_to.
An unsupported filter parameter returns 422. See
Filtering collections
for matching semantics.
Sorting
GET .../calendar_events?sort= orders the list by: id, customer_id, user_id, start_time, duration, created_at.
Prefix a field with - for descending; comma-separate for tie-breakers. An
unsupported field returns 422. See
Sorting collections.
Related
- Requests and Responses — envelope, errors, pagination, and rate limits.
- Authentication — tokens and the
Authorizationheader.