docs: v2 rolling window and authentication (#17825)

* docs: booking window rolling description

* docs: v2 auth and navigating endpoints

* Update apps/api/v2/swagger/documentation.json

* Update docs/api-reference/v2/introduction.mdx

* Update docs/api-reference/v2/introduction.mdx

* Update docs/api-reference/v2/introduction.mdx

* docs: refresh and force-refresh endpoints

* docs: booking fields and toasts guides

* fix docs

* fix: bookings docs

* docs: booking-redirects usebooking

* Update booking-fields.mdx

* Update booking-fields.mdx

* Update booking-fields.mdx

* Update booking-window.input.ts

* Update replacing-toasts.mdx

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2024-12-03 17:53:14 +01:00
1 parent 6378729962
commit 3222be9171
23 files changed
+1499 -135

No files matched your search

+48 -1
View File
@@ -5,7 +5,17 @@ description: 'Introduction to Cal.com API v2 endpoints'
## Authentication
The Cal.com API uses API keys to authenticate requests. You can view and manage your API keys in your settings page under the security tab in Cal.com.
The Cal.com API has 3 authentication methods:
1. API key
2. Platform OAuth client credentials
3. Managed user access token
If you are a platform customer you don't need an API key and must instead use OAuth credentials or a managed user access token. We cover when to use which below.
### 1. API key
You can view and manage your API keys in your settings page under the security tab in Cal.com.
<img src="/images/i1600x899-DllqhV6w_3Vj_oxtjov.png" />
@@ -24,3 +34,40 @@ Authentication to the API is performed via the Authorization header. For example
in your request header.
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
### 2. OAuth client credentials
You need to use OAuth credentials when:
1. Managing managed users [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user)
2. Creating OAuth client webhooks [API reference](https://cal.com/docs/api-reference/v2/platform-webhooks/create-a-webhook)
3. Refreshing tokens of a managed user [API reference](https://cal.com/docs/api-reference/v2/oauth/post-v2oauth-refresh)
4. Teams related endpoints: Managing organization teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team), adding managed users as members to teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership), creating team event types [API reference](https://cal.com/docs/api-reference/v2/orgs-event-types/create-an-event-type).
OAuth credentials can be accessed in the platform dashboard https://app.cal.com/settings/platform after you have created an OAuth client. Each one has an ID and secret. You then need to pass them as request headers:
1. `x-cal-client-id` - ID of the OAuth client.
2. `x-cal-secret-key` - secret of the OAuth client.
### 3. Managed user access token
After you create a managed user you will receive its access and refresh tokens. The response also includes managed user's id, so we recommend you to add new properties to your users table calAccessToken, calRefreshToken and calManagedUserId to store this information.
You need to use access token when managing managed user's:
1. Schedules [API reference](https://cal.com/docs/api-reference/v2/schedules/create-a-schedule)
2. Event types [API reference](https://cal.com/docs/api-reference/v2/event-types/create-an-event-type)
3. Bookings - some endpoints like creating a booking is public, but some like getting all managed user's bookings require managed user's access token [API reference](https://cal.com/docs/api-reference/v2/bookings/get-all-bookings)
It is passed as an authorization bearer request header Authorization: Bearer \<access-token\>.
Validity period: access tokens are valid for 60 minutes and refresh tokens for 1 year, and tokens can be refreshed using the refresh endpoint [API reference](https://cal.com/docs/api-reference/v2/oauth/post-v2oauth-refresh). After refreshing you will receive the new access and refresh tokens that you have to store in your database.
Recovering tokens: if you ever lose managed user's access or refresh tokens, you can force refresh them using the OAuth client credentials and store them in your database [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/force-refresh-tokens).
## Navigating endpoints
Platform customers have the following endpoints available:
1. Endpoints prefixed with "Platform".
2. Endpoints with no prefix e.g "Bookings", "Event Types".
3. If you are at least on the ESSENTIALS plan, then all endpoints prefixed with "Orgs" except "Orgs / Attributes".
Non-platform customers have all the endpoints except the ones prefixed with "Platform".
+608 -49
View File
@@ -342,6 +342,7 @@
"post": {
"operationId": "OAuthClientUsersController_forceRefresh",
"summary": "Force refresh tokens",
"description": "If you have lost managed user access or refresh token, then you can get new ones by using OAuth credentials.\n Each access token is valid for 60 minutes and each refresh token for 1 year. Make sure to store them later in your database, for example, by updating the User model to have `calAccessToken` and `calRefreshToken` columns.",
"parameters": [
{
"name": "userId",
@@ -375,6 +376,55 @@
"tags": ["Platform / Managed Users"]
}
},
"/v2/oauth/{clientId}/refresh": {
"post": {
"operationId": "OAuthFlowController_refreshTokens",
"summary": "Refresh managed user tokens",
"description": "If managed user access token is expired then get a new one using this endpoint. Each access token is valid for 60 minutes and \n each refresh token for 1 year. Make sure to store them later in your database, for example, by updating the User model to have `calAccessToken` and `calRefreshToken` columns.",
"parameters": [
{
"name": "clientId",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "x-cal-secret-key",
"required": true,
"in": "header",
"description": "OAuth client secret key.",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RefreshTokenInput"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/KeysResponseDto"
}
}
}
}
},
"tags": ["Platform / Managed Users"]
}
},
"/v2/oauth-clients/{clientId}/webhooks": {
"post": {
"operationId": "OAuthClientWebhooksController_createOAuthClientWebhook",
@@ -4207,53 +4257,6 @@
"tags": ["Me"]
}
},
"/v2/oauth/{clientId}/refresh": {
"post": {
"operationId": "OAuthFlowController_refreshAccessToken",
"parameters": [
{
"name": "clientId",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "x-cal-secret-key",
"required": true,
"in": "header",
"description": "OAuth client secret key.",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RefreshTokenInput"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/KeysResponseDto"
}
}
}
}
},
"tags": ["OAuth", "Managed users"]
}
},
"/v2/schedules": {
"post": {
"operationId": "SchedulesController_2024_06_11_createSchedule",
@@ -6064,7 +6067,7 @@
"rolling": {
"type": "boolean",
"example": true,
"description": "If true, the window will be rolling aka from the moment that someone is trying to book this event. Otherwise it will be specified amount of days from the current date."
"description": "\n Determines the behavior of the booking window:\n - If **true**, the window is rolling. This means the number of available days will always equal the specified 'value' \n and adjust dynamically as bookings are made. For example, if 'value' is 3 and availability is only on Mondays, \n a booker attempting to schedule on November 10 will see slots on November 11, 18, and 25. As one of these days \n becomes fully booked, a new day (e.g., December 2) will open up to ensure 3 available days are always visible.\n - If **false**, the window is fixed. This means the booking window only considers the next 'value' days from the\n moment someone is trying to book. For example, if 'value' is 3, availability is only on Mondays, and the current \n date is November 10, the booker will only see slots on November 11 because the window is restricted to the next \n 3 calendar days (November 10–12).\n "
}
},
"required": ["type", "value"]
@@ -6085,7 +6088,7 @@
"rolling": {
"type": "boolean",
"example": true,
"description": "If true, the window will be rolling aka from the moment that someone is trying to book this event. Otherwise it will be specified amount of days from the current date."
"description": "\n Determines the behavior of the booking window:\n - If **true**, the window is rolling. This means the number of available days will always equal the specified 'value' \n and adjust dynamically as bookings are made. For example, if 'value' is 3 and availability is only on Mondays, \n a booker attempting to schedule on November 10 will see slots on November 11, 18, and 25. As one of these days \n becomes fully booked, a new day (e.g., December 2) will open up to ensure 3 available days are always visible.\n - If **false**, the window is fixed. This means the booking window only considers the next 'value' days from the\n moment someone is trying to book. For example, if 'value' is 3, availability is only on Mondays, and the current \n date is November 10, the booker will only see slots on November 11 because the window is restricted to the next \n 3 calendar days (November 10–12).\n "
}
},
"required": ["type", "value"]
@@ -11992,6 +11995,326 @@
"recurringBookingUid"
]
},
"SeatedAttendee": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "John Doe"
},
"timeZone": {
"type": "string",
"example": "America/New_York"
},
"language": {
"type": "string",
"enum": [
"ar",
"ca",
"de",
"es",
"eu",
"he",
"id",
"ja",
"lv",
"pl",
"ro",
"sr",
"th",
"vi",
"az",
"cs",
"el",
"es-419",
"fi",
"hr",
"it",
"km",
"nl",
"pt",
"ru",
"sv",
"tr",
"zh-CN",
"bg",
"da",
"en",
"et",
"fr",
"hu",
"iw",
"ko",
"no",
"pt-BR",
"sk",
"ta",
"uk",
"zh-TW"
],
"example": "en"
},
"absent": {
"type": "boolean",
"example": false
},
"seatUid": {
"type": "string",
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
},
"bookingFieldsResponses": {
"type": "object",
"description": "Booking field responses consisting of an object with booking field slug as keys and user response as values.",
"example": {
"customField": "customValue"
}
},
"metadata": {
"type": "object",
"example": {
"key": "value"
}
}
},
"required": ["name", "timeZone", "absent", "seatUid"]
},
"CreateSeatedBookingOutput_2024_08_13": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 123
},
"uid": {
"type": "string",
"example": "booking_uid_123"
},
"title": {
"type": "string",
"example": "Consultation"
},
"description": {
"type": "string",
"example": "Learn how to integrate scheduling into marketplace."
},
"hosts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Host"
}
},
"status": {
"type": "string",
"enum": ["cancelled", "accepted", "rejected", "pending"],
"example": "accepted"
},
"cancellationReason": {
"type": "string",
"example": "User requested cancellation"
},
"reschedulingReason": {
"type": "string",
"example": "User rescheduled the event"
},
"rescheduledFromUid": {
"type": "string",
"example": "previous_uid_123"
},
"start": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"end": {
"type": "string",
"example": "2024-08-13T16:30:00Z"
},
"duration": {
"type": "number",
"example": 60
},
"eventTypeId": {
"type": "number",
"example": 50,
"deprecated": true,
"description": "Deprecated - rely on 'eventType' object containing the id instead."
},
"eventType": {
"$ref": "#/components/schemas/EventType"
},
"meetingUrl": {
"type": "string",
"description": "Deprecated - rely on 'location' field instead.",
"example": "https://example.com/recurring-meeting",
"deprecated": true
},
"location": {
"type": "string",
"example": "https://example.com/meeting"
},
"absentHost": {
"type": "boolean",
"example": true
},
"createdAt": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"metadata": {
"type": "object",
"example": {
"key": "value"
}
},
"seatUid": {
"type": "string",
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
},
"attendees": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SeatedAttendee"
}
}
},
"required": [
"id",
"uid",
"title",
"description",
"hosts",
"status",
"start",
"end",
"duration",
"eventTypeId",
"eventType",
"absentHost",
"createdAt",
"seatUid",
"attendees"
]
},
"CreateRecurringSeatedBookingOutput_2024_08_13": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 123
},
"uid": {
"type": "string",
"example": "booking_uid_123"
},
"title": {
"type": "string",
"example": "Consultation"
},
"description": {
"type": "string",
"example": "Learn how to integrate scheduling into marketplace."
},
"hosts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Host"
}
},
"status": {
"type": "string",
"enum": ["cancelled", "accepted", "rejected", "pending"],
"example": "accepted"
},
"cancellationReason": {
"type": "string",
"example": "User requested cancellation"
},
"reschedulingReason": {
"type": "string",
"example": "User rescheduled the event"
},
"rescheduledFromUid": {
"type": "string",
"example": "previous_uid_123"
},
"start": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"end": {
"type": "string",
"example": "2024-08-13T16:30:00Z"
},
"duration": {
"type": "number",
"example": 60
},
"eventTypeId": {
"type": "number",
"example": 50,
"deprecated": true,
"description": "Deprecated - rely on 'eventType' object containing the id instead."
},
"eventType": {
"$ref": "#/components/schemas/EventType"
},
"meetingUrl": {
"type": "string",
"description": "Deprecated - rely on 'location' field instead.",
"example": "https://example.com/recurring-meeting",
"deprecated": true
},
"location": {
"type": "string",
"example": "https://example.com/meeting"
},
"absentHost": {
"type": "boolean",
"example": true
},
"createdAt": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"metadata": {
"type": "object",
"example": {
"key": "value"
}
},
"seatUid": {
"type": "string",
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
},
"attendees": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SeatedAttendee"
}
},
"recurringBookingUid": {
"type": "string",
"example": "recurring_uid_987"
}
},
"required": [
"id",
"uid",
"title",
"description",
"hosts",
"status",
"start",
"end",
"duration",
"eventTypeId",
"eventType",
"absentHost",
"createdAt",
"seatUid",
"attendees",
"recurringBookingUid"
]
},
"CreateBookingOutput_2024_08_13": {
"type": "object",
"properties": {
@@ -12010,6 +12333,15 @@
"items": {
"$ref": "#/components/schemas/RecurringBookingOutput_2024_08_13"
}
},
{
"$ref": "#/components/schemas/CreateSeatedBookingOutput_2024_08_13"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/CreateRecurringSeatedBookingOutput_2024_08_13"
}
}
],
"description": "Booking data, which can be either a BookingOutput object or an array of RecurringBookingOutput objects"
@@ -12017,6 +12349,233 @@
},
"required": ["status", "data"]
},
"GetSeatedBookingOutput_2024_08_13": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 123
},
"uid": {
"type": "string",
"example": "booking_uid_123"
},
"title": {
"type": "string",
"example": "Consultation"
},
"description": {
"type": "string",
"example": "Learn how to integrate scheduling into marketplace."
},
"hosts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Host"
}
},
"status": {
"type": "string",
"enum": ["cancelled", "accepted", "rejected", "pending"],
"example": "accepted"
},
"cancellationReason": {
"type": "string",
"example": "User requested cancellation"
},
"reschedulingReason": {
"type": "string",
"example": "User rescheduled the event"
},
"rescheduledFromUid": {
"type": "string",
"example": "previous_uid_123"
},
"start": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"end": {
"type": "string",
"example": "2024-08-13T16:30:00Z"
},
"duration": {
"type": "number",
"example": 60
},
"eventTypeId": {
"type": "number",
"example": 50,
"deprecated": true,
"description": "Deprecated - rely on 'eventType' object containing the id instead."
},
"eventType": {
"$ref": "#/components/schemas/EventType"
},
"meetingUrl": {
"type": "string",
"description": "Deprecated - rely on 'location' field instead.",
"example": "https://example.com/recurring-meeting",
"deprecated": true
},
"location": {
"type": "string",
"example": "https://example.com/meeting"
},
"absentHost": {
"type": "boolean",
"example": true
},
"createdAt": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"metadata": {
"type": "object",
"example": {
"key": "value"
}
},
"attendees": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SeatedAttendee"
}
}
},
"required": [
"id",
"uid",
"title",
"description",
"hosts",
"status",
"start",
"end",
"duration",
"eventTypeId",
"eventType",
"absentHost",
"createdAt",
"attendees"
]
},
"GetRecurringSeatedBookingOutput_2024_08_13": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 123
},
"uid": {
"type": "string",
"example": "booking_uid_123"
},
"title": {
"type": "string",
"example": "Consultation"
},
"description": {
"type": "string",
"example": "Learn how to integrate scheduling into marketplace."
},
"hosts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Host"
}
},
"status": {
"type": "string",
"enum": ["cancelled", "accepted", "rejected", "pending"],
"example": "accepted"
},
"cancellationReason": {
"type": "string",
"example": "User requested cancellation"
},
"reschedulingReason": {
"type": "string",
"example": "User rescheduled the event"
},
"rescheduledFromUid": {
"type": "string",
"example": "previous_uid_123"
},
"start": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"end": {
"type": "string",
"example": "2024-08-13T16:30:00Z"
},
"duration": {
"type": "number",
"example": 60
},
"eventTypeId": {
"type": "number",
"example": 50,
"deprecated": true,
"description": "Deprecated - rely on 'eventType' object containing the id instead."
},
"eventType": {
"$ref": "#/components/schemas/EventType"
},
"meetingUrl": {
"type": "string",
"description": "Deprecated - rely on 'location' field instead.",
"example": "https://example.com/recurring-meeting",
"deprecated": true
},
"location": {
"type": "string",
"example": "https://example.com/meeting"
},
"absentHost": {
"type": "boolean",
"example": true
},
"createdAt": {
"type": "string",
"example": "2024-08-13T15:30:00Z"
},
"metadata": {
"type": "object",
"example": {
"key": "value"
}
},
"attendees": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SeatedAttendee"
}
},
"recurringBookingUid": {
"type": "string",
"example": "recurring_uid_987"
}
},
"required": [
"id",
"uid",
"title",
"description",
"hosts",
"status",
"start",
"end",
"duration",
"eventTypeId",
"eventType",
"absentHost",
"createdAt",
"attendees",
"recurringBookingUid"
]
},
"GetBookingOutput_2024_08_13": {
"type": "object",
"properties": {