Reonic Appointments API
Appointments on Reonic-hosted calendars only. External calendars (Google, Microsoft) cannot be read or written through the API.
Appointments on Reonic-hosted calendars only. External calendars (Google, Microsoft) cannot be read or written through the API.
openapi: 3.1.0
info:
title: Reonic REST Api v3 Activities Appointments API
description: 'The Reonic REST API v3 provides programmatic access to create and manage resources. The API follows REST principles and returns responses in JSON format. Authentication is required via an API key passed in the X-Authorization header.
## Errors
All endpoints return errors with the same JSON shape:
```json
{ "message": "human-readable description" }
```
`400` responses additionally include an `errors` field with per-field validation details.
The HTTP status code identifies the cause:
| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad Request | Path params, query string, or request body failed validation. Inspect `errors` for the field-level breakdown. |
| `401` | Unauthorized | The `X-Authorization` header is missing, malformed, does not match an active API key, or belongs to a different API version. The response never indicates which check failed; check that the key matches the endpoint version. API v3 endpoints require a v3 key with the `rnc_v3_` prefix. |
| `403` | Forbidden | The API key is read-only and the request targeted a write endpoint (`POST`). Issue a key with write access. |
| `404` | Not Found | A resource referenced by a path id does not exist or is not visible to your workspace. |
| `429` | Too Many Requests | The per-client rate limit was exceeded. See **Rate limiting** below. |
| `500` | Internal Server Error | Unexpected failure. Safe to retry once; if it persists, contact support. |
| `503` | Service Unavailable | A backing dependency is temporarily unavailable. Retry with exponential backoff. |
## Rate limiting
Limits are shared across all API keys you hold and reset on a 1-minute window. Two buckets:
| Bucket | Limit | Applies to |
|--------|-------|------------|
| `cached` | 500 / min | `GET` requests served from the response cache |
| `uncached` | 30 / min | Cache misses, `GET` requests sent with `Reonic-Cache-Control: no-cache`, and all `POST` requests |
Every response includes:
- `X-RateLimit-Bucket` — `cached` or `uncached`
- `X-RateLimit-Limit` — the bucket''s ceiling (`500` or `30`)
- `X-RateLimit-Remaining` — calls left in the current window
- `X-RateLimit-Reset` — Unix epoch seconds at which the window resets
- `X-RateLimit-Policy` — `<limit>;w=60`
`429` responses additionally set `Retry-After` (in seconds). Wait at least that long before retrying.
## Caching and Reonic-Cache-Control
`GET` responses are cached for up to 1 hour. Identical requests (same path and query) on the same API key return the cached result. To force a fresh read, send `Reonic-Cache-Control: no-cache`; the response is then refreshed and re-cached. Forced refreshes count against the `uncached` rate-limit bucket.
The standard `Cache-Control` header is not honored. Use `Reonic-Cache-Control` to control caching behavior.
## Authentication
Every request must include your API key in the `X-Authorization` header:
```
X-Authorization: <your-api-key>
```
API keys are issued from the Reonic web app and look like `rnc_v3_…`. Send the full value, including the prefix.
'
version: 3.2.0
contact:
email: kontakt@reonic.de
url: https://reonic.com
name: Reonic GmbH
servers:
- url: '{apiBaseUrl}/rest/v3/'
security:
- X-Authorization: []
tags:
- name: Appointments
description: Appointments on Reonic-hosted calendars only. External calendars (Google, Microsoft) cannot be read or written through the API.
paths:
/appointments:
get:
summary: List appointments
description: 'Lists appointments on Reonic calendars in a paginated format.
**Allowed API keys:** Read-only, Read and Write'
tags:
- Appointments
parameters:
- schema:
type:
- array
- 'null'
items:
type: string
format: uuid
minItems: 1
maxItems: 100
description: Comma-separated list or repeated query param of calendar IDs to fetch appointments for.
examples:
- 123e4567-e89b-12d3-a456-426614174000
- 123e4567-e89b-12d3-a456-426614174000, 123e4567-e89b-12d3-a456-426614174002
required: false
description: Comma-separated list or repeated query param of calendar IDs to fetch appointments for.
name: calendarIds
in: query
- schema:
type: string
format: uuid
description: Return only appointments linked to the given residential project. Mutually exclusive with `commercialProjectId`. Reference to [**Residential Projects**](#tag/residential-projects)
required: false
description: Return only appointments linked to the given residential project. Mutually exclusive with `commercialProjectId`. Reference to [**Residential Projects**](#tag/residential-projects)
name: residentialProjectId
in: query
- schema:
type: string
format: uuid
description: Return only appointments linked to the given commercial project. Mutually exclusive with `residentialProjectId`. Reference to [**Commercial Projects**](#tag/commercial-projects)
required: false
description: Return only appointments linked to the given commercial project. Mutually exclusive with `residentialProjectId`. Reference to [**Commercial Projects**](#tag/commercial-projects)
name: commercialProjectId
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where start is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where start is after this datetime (exclusive)
name: start.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Defaults to the day one year from now.
example: '2026-01-01T15:30:00.000Z'
required: false
description: Defaults to the day one year from now.
name: start.lt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Defaults to now, so that by default only upcoming appointments are returned.
example: '2026-01-01T15:30:00.000Z'
required: false
description: Defaults to now, so that by default only upcoming appointments are returned.
name: end.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where end is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where end is before this datetime (exclusive)
name: end.lt
in: query
- schema:
type: integer
minimum: 1
default: 1
description: 'Page number, starting from 1. Default: 1.'
required: false
description: 'Page number, starting from 1. Default: 1.'
name: page
in: query
- schema:
type: integer
minimum: 1
maximum: 200
default: 50
description: 'Number of items per page. Default: 50. Max: 200.'
required: false
description: 'Number of items per page. Default: 50. Max: 200.'
name: itemsPerPage
in: query
- schema:
type:
- string
- 'null'
default: start
description: 'Sort order. Use field names for ascending (e.g. "createdAt"), minus sign for descending (e.g. "-createdAt"). Chain with commas (e.g. "createdAt,editedAt"). Sortable fields: start, end. Defaults to start.'
examples:
- start
- -start
- end,-start
required: false
description: 'Sort order. Use field names for ascending (e.g. "createdAt"), minus sign for descending (e.g. "-createdAt"). Chain with commas (e.g. "createdAt,editedAt"). Sortable fields: start, end. Defaults to start.'
name: sort
in: query
- schema:
type: string
example: no-cache
required: false
name: Reonic-Cache-Control
in: header
description: Set to 'no-cache' to bypass the 1-hour response cache and force a fresh read. The fresh response is then written back to the cache for subsequent callers. Forced refreshes count against the uncached rate-limit bucket (30/min); only cache hits count against the cached bucket (500/min).
responses:
'200':
description: Paginated list of appointments
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
calendarId:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
title:
type: string
default: ''
customerPortalTitle:
type:
- string
- 'null'
description:
type:
- string
- 'null'
customerPortalDescription:
type:
- string
- 'null'
visibleInCustomerPortal:
type: boolean
description: Whether this appointment is visible in the customer portal or not.
start:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
end:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
allDay:
type: boolean
location:
type:
- string
- 'null'
residentialProjectId:
type:
- string
- 'null'
format: uuid
commercialProjectId:
type:
- string
- 'null'
format: uuid
attendeeIds:
type: array
items:
type: string
format: uuid
description: List of users attending this appointment. Reference to [**Users**](#tag/users)
required:
- id
- calendarId
- customerPortalTitle
- description
- customerPortalDescription
- visibleInCustomerPortal
- start
- end
- allDay
- location
- residentialProjectId
- commercialProjectId
- attendeeIds
pagination:
type: object
properties:
page:
type: integer
minimum: 1
description: Current page number
perPage:
type: integer
minimum: 1
description: Number of items per page
total:
type: integer
minimum: 0
description: Total number of items across all pages
totalPages:
type: integer
minimum: 1
next:
type:
- string
- 'null'
description: Path to the next page, or null if there is no next page
prev:
type:
- string
- 'null'
description: Path to the previous page, or null if there is no previous page
required:
- page
- perPage
- total
- totalPages
- next
- prev
required:
- data
- pagination
/appointments/create:
post:
summary: Create appointment
description: 'Create an appointment on a Reonic calendar.
**Allowed API keys:** Read and Write'
tags:
- Appointments
requestBody:
content:
application/json:
schema:
type: object
properties:
calendarId:
type: string
format: uuid
title:
type: string
minLength: 1
maxLength: 2000
customerPortalTitle:
type:
- string
- 'null'
minLength: 1
maxLength: 2000
description:
type:
- string
- 'null'
minLength: 1
maxLength: 5000
customerPortalDescription:
type:
- string
- 'null'
minLength: 1
maxLength: 5000
visibleInCustomerPortal:
type: boolean
default: false
description: 'Whether this appointment is visible in the customer portal or not. Default: `false`'
start:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
description: Appointment start. When `allDay` is `true`, only the date portion is used and the time component is ignored.
end:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
description: Appointment end. When `allDay` is `true`, only the date portion is used and the time component is ignored.
allDay:
type: boolean
description: When `true`, `start` and `end` are treated as dates only — the time component is ignored and `end` must be at least one full day after `start`. When `false`, `start` and `end` are treated as exact datetimes.
attendeeIds:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 100
description: Users attending this appointment. Reference to [**Users**](#tag/users)
location:
type:
- string
- 'null'
minLength: 1
maxLength: 2000
residentialProjectId:
type:
- string
- 'null'
format: uuid
description: Mutually exclusive with `commercialProjectId`. Reference to [**Residential Projects**](#tag/residential-projects)
commercialProjectId:
type:
- string
- 'null'
format: uuid
description: Mutually exclusive with `residentialProjectId`. Reference to [**Commercial Projects**](#tag/commercial-projects)
required:
- calendarId
- title
- start
- end
- allDay
additionalProperties: false
responses:
'201':
description: The created appointment
content:
application/json:
schema:
type: object
properties:
id:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
calendarId:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
title:
type: string
default: ''
customerPortalTitle:
type:
- string
- 'null'
description:
type:
- string
- 'null'
customerPortalDescription:
type:
- string
- 'null'
visibleInCustomerPortal:
type: boolean
description: Whether this appointment is visible in the customer portal or not.
start:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
end:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
allDay:
type: boolean
location:
type:
- string
- 'null'
residentialProjectId:
type:
- string
- 'null'
format: uuid
commercialProjectId:
type:
- string
- 'null'
format: uuid
attendeeIds:
type: array
items:
type: string
format: uuid
description: List of users attending this appointment. Reference to [**Users**](#tag/users)
required:
- id
- calendarId
- customerPortalTitle
- description
- customerPortalDescription
- visibleInCustomerPortal
- start
- end
- allDay
- location
- residentialProjectId
- commercialProjectId
- attendeeIds
/appointments/{appointmentId}/update:
post:
summary: Update appointment
description: 'Update fields of an appointment on a Reonic calendar. Omit fields to leave them untouched, send `null` to clear them (where possible) or send a value to replace it.
**Allowed API keys:** Read and Write'
tags:
- Appointments
parameters:
- schema:
type: string
format: uuid
required: true
name: appointmentId
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
title:
type: string
minLength: 1
maxLength: 2000
customerPortalTitle:
type:
- string
- 'null'
minLength: 1
maxLength: 2000
description:
type:
- string
- 'null'
minLength: 1
maxLength: 5000
customerPortalDescription:
type:
- string
- 'null'
minLength: 1
maxLength: 5000
visibleInCustomerPortal:
type: boolean
description: Whether this appointment is visible in the customer portal or not.
start:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
description: Appointment start. When `allDay` is `true`, only the date portion is used and the time component is ignored.
end:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
description: Appointment end. When `allDay` is `true`, only the date portion is used and the time component is ignored.
allDay:
type: boolean
description: When `true`, `start` and `end` are treated as dates only — the time component is ignored and `end` must be at least one full day after `start`. When `false`, `start` and `end` are treated as exact datetimes.
attendeeIds:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 100
description: Users attending this appointment. Reference to [**Users**](#tag/users)
location:
type:
- string
- 'null'
minLength: 1
maxLength: 2000
residentialProjectId:
type:
- string
- 'null'
format: uuid
description: Mutually exclusive with `commercialProjectId`. Reference to [**Residential Projects**](#tag/residential-projects)
commercialProjectId:
type:
- string
- 'null'
format: uuid
description: Mutually exclusive with `residentialProjectId`. Reference to [**Commercial Projects**](#tag/commercial-projects)
additionalProperties: false
responses:
'200':
description: The updated appointment
content:
application/json:
schema:
type: object
properties:
id:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
calendarId:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
title:
type: string
default: ''
customerPortalTitle:
type:
- string
- 'null'
description:
type:
- string
- 'null'
customerPortalDescription:
type:
- string
- 'null'
visibleInCustomerPortal:
type: boolean
description: Whether this appointment is visible in the customer portal or not.
start:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
end:
type: string
format: date-time
example: '2026-01-01T15:30:00.000Z'
allDay:
type: boolean
location:
type:
- string
- 'null'
residentialProjectId:
type:
- string
- 'null'
format: uuid
commercialProjectId:
type:
- string
- 'null'
format: uuid
attendeeIds:
type: array
items:
type: string
format: uuid
description: List of users attending this appointment. Reference to [**Users**](#tag/users)
required:
- id
- calendarId
- customerPortalTitle
- description
- customerPortalDescription
- visibleInCustomerPortal
- start
- end
- allDay
- location
- residentialProjectId
- commercialProjectId
- attendeeIds
/appointments/{appointmentId}/delete:
post:
summary: Delete appointment
description: 'Delete an appointment on a Reonic calendar.
**Allowed API keys:** Read and Write'
tags:
- Appointments
parameters:
- schema:
type: string
format: uuid
required: true
name: appointmentId
in: path
responses:
'200':
description: ID of the deleted appointment
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
format: uuid
required:
- id
additionalProperties: false
required:
- data
components:
securitySchemes:
X-Authorization:
type: apiKey
in: header
name: X-Authorization
x-tagGroups:
- name: People
tags:
- Contacts
- Users
- Teams
- name: Projects
tags:
- Residential Projects
- Commercial Projects
- name: Working on a project
tags:
- Notes
- Tasks
- Files
- File Folders
- Activities
- Time Tracking
- Checklists
- Checklist Templates
- Signature Requests
- name: Calendar
tags:
- Calendars
- Calendar Categories
- Appointments
- name: Catalog
tags:
- Components
- Planning Templates
- Planning Packages
- Offer Templates
- name: Workspace setup
tags:
- Kanban Boards
- Kanban Columns
- Tags
- Lead Sources
- name: Wiki
tags:
- Wiki
- name: Services
tags:
- Photogrammetry
- name: API helpers
tags:
- Upload
- Links
- name: Integrations
tags:
- Webhooks
- name: Guides
tags:
- Migrating from API v2 to v3
- Changelog