
## Create event

`POST /v1/calendar-events`

Creates a new event in the specified calendar.

## Request fields (body)

| Field | Type | Req. | Description |
|------|-----|:-----:|---------|
| `type` | string | yes | Calendar type: `user`, `group`, `company_calendar` |
| `ownerId` | number | yes | Calendar owner ID: employee (`GET /v1/users`) or workgroup |
| `name` | string | yes | Event title |
| `from` | datetime | yes | Event start in ISO 8601. Accepts a string with an explicit offset (`2026-06-10T10:00:00+00:00`), in UTC (`2026-06-10T07:00:00Z`), or without a zone (`2026-06-10T10:00:00`) |
| `to` | datetime | yes | Event end in ISO 8601. Accepts a string with an explicit offset (`2026-06-10T11:00:00+00:00`), in UTC (`2026-06-10T08:00:00Z`), or without a zone (`2026-06-10T11:00:00`) |
| `timezoneFrom` | string | no | Event start timezone (IANA name: `UTC`, `Asia/Almaty`, `UTC`). Without it, the timezone of the employee who owns the API key is used |
| `timezoneTo` | string | no | Event end timezone (IANA name) |
| `description` | string | no | Description |
| `sectionId` | number | no | Calendar section ID. If the field is not passed, a new section is created on every call. To have events written to a single section, pass the `sectionId` of an existing section. The ID of an existing section is returned by [`GET /v1/calendar-events`](./list.md) in the `sectionId` field of any previously created event |
| `skipTime` | boolean | no | All-day event. When `true`, the time in `from`/`to` is ignored and the duration is fixed at 24 hours |
| `importance` | string | no | `high`, `normal`, `low` |
| `accessibility` | string | no | Availability: `busy`, `quest` (tentative), `free`, `absent` |
| `location` | string | no | Venue |
| `color` | string | no | Event color (HEX, `#RRGGBB`) |
| `attendees` | number[] | no | Array of invited employee IDs. List: `GET /v1/users`. **Write-only** — in the response, attendees are returned in the `attendeeList`, `attendeesCodes` fields. See [Event fields](./fields.md) |
| `remind` | array | no | Reminder settings. Each item: `{type: 'min' \| 'hour' \| 'day', count: <number>}` |
| `rrule` | object | no | Recurrence schedule of a recurring event. Field structure and an example — the [Recurring event](#recurring-event) section below |
| `isPrivate` | boolean | no | Private event — details are hidden from other users |
| `isMeeting` | boolean | no | Meeting event with invitations |

Full field list: [`GET /v1/calendar-events/fields`](./fields.md).

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/calendar-events" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "user",
    "ownerId": 1,
    "name": "Team call",
    "from": "2026-06-10T10:00:00",
    "to": "2026-06-10T11:00:00",
    "timezoneFrom": "UTC",
    "timezoneTo": "UTC",
    "description": "Weekly sync",
    "accessibility": "busy",
    "sectionId": 3
  }'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/calendar-events" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "user",
    "ownerId": 1,
    "name": "Team call",
    "from": "2026-06-10T10:00:00",
    "to": "2026-06-10T11:00:00",
    "timezoneFrom": "UTC",
    "timezoneTo": "UTC",
    "description": "Weekly sync",
    "accessibility": "busy",
    "sectionId": 3
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/calendar-events', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'user',
    ownerId: 1,
    name: 'Team call',
    from: '2026-06-10T10:00:00',
    to: '2026-06-10T11:00:00',
    timezoneFrom: 'UTC',
    timezoneTo: 'UTC',
    description: 'Weekly sync',
    accessibility: 'busy',
    sectionId: 3,
  }),
})

const { success, data } = await res.json()
console.log('Event ID:', data.id)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/calendar-events', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'user',
    ownerId: 1,
    name: 'Team call',
    from: '2026-06-10T10:00:00',
    to: '2026-06-10T11:00:00',
    timezoneFrom: 'UTC',
    timezoneTo: 'UTC',
    description: 'Weekly sync',
    accessibility: 'busy',
    sectionId: 3,
  }),
})

const { success, data } = await res.json()
```

## Recurring event

To create a recurring event, pass the `rrule` field as an object. Request:

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/calendar-events" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "user",
    "ownerId": 1,
    "name": "Team call",
    "from": "2026-07-13T10:00:00",
    "to": "2026-07-13T11:00:00",
    "timezoneFrom": "UTC",
    "timezoneTo": "UTC",
    "rrule": {
      "FREQ": "WEEKLY",
      "INTERVAL": 1,
      "BYDAY": ["MO", "WE"],
      "UNTIL": "2026-09-30"
    }
  }'
```

A single event with one `id` is created — the list (`GET /v1/calendar-events`) will return one item per occurrence in the series, all sharing a common `parentId`. Deleting the event (`DELETE /v1/calendar-events/:id`) removes the entire series.

`rrule` fields:

| Field | Type | Description |
|------|-----|---------|
| `FREQ` | string | Periodicity: `DAILY`, `WEEKLY`, `MONTHLY`, `YEARLY` |
| `INTERVAL` | number | Interval. `1` — every cycle, `2` — every other, and so on |
| `BYDAY` | string[] | Days of the week for `WEEKLY`: `SU`, `MO`, `TU`, `WE`, `TH`, `FR`, `SA` |
| `UNTIL` | date | Series end date in `YYYY-MM-DD` format. Alternative — `COUNT` |
| `COUNT` | number | Number of repetitions. Alternative — `UNTIL` |

## Response fields

The created event object with all fields — see [Event fields](./fields.md).

The URL of the event card in Bitrix24 depends on the calendar type:

| `type` | URL |
|---|---|
| `user` | `https://<portal>.bitrix24.com/company/personal/user/<ownerId>/calendar/?EVENT_ID=<id>&EVENT_DATE=<dd.mm.yyyy>` |
| `group` | `https://<portal>.bitrix24.com/workgroups/group/<ownerId>/calendar/?EVENT_ID=<id>&EVENT_DATE=<dd.mm.yyyy>` |
| `company_calendar` | `https://<portal>.bitrix24.com/calendar/?EVENT_ID=<id>&EVENT_DATE=<dd.mm.yyyy>` |

`<dd.mm.yyyy>` — the event start date (the `from` field) in "day.month.year" format separated by dots. `<portal>` — your Bitrix24 account domain. Access is limited by the employee's permissions in Bitrix24.

## Response example

```json
{
  "success": true,
  "data": {
    "id": 7773,
    "parentId": 7773,
    "deleted": false,
    "type": "user",
    "ownerId": 1,
    "name": "Team call",
    "from": "2026-06-10T10:00:00+00:00",
    "to": "2026-06-10T11:00:00+00:00",
    "skipTime": false,
    "durationSeconds": 3600,
    "createdBy": 1,
    "dateCreate": "06/05/2026 09:12:00 am",
    "updatedAt": "06/05/2026 09:12:00 am",
    "description": "Weekly sync",
    "accessibility": "busy",
    "importance": "normal",
    "isMeeting": false,
    "meetingStatus": "H",
    "meetingHost": 1,
    "sectionId": 3,
    "attendeeList": [
      { "id": 1, "entryId": "7773", "status": "H" }
    ]
  }
}
```

## Error response example

422 — a required field was not passed:

```json
{
  "success": false,
  "error": {
    "code": "BITRIX_ERROR",
    "message": "Required parameter \"name\" is not set for the \"calendar.event.add\" method"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 422 | `BITRIX_ERROR` | A required field was not passed (`type`, `ownerId`, `name`, `from`, `to`) |
| 400 | `READONLY_FIELD` | A read-only field was passed in the request body (`id`, `createdBy`, `dateCreate`, `updatedAt`) |
| 403 | `SCOPE_DENIED` | The API key does not have the `calendar` scope |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |

Full list of common API errors — [Errors](/docs/errors).

## Known specifics

**Section buildup when creating without `sectionId`.** If the `sectionId` field is not passed, a new calendar section is created on every call. Over a series of calls without `sectionId`, empty sections accumulate in the employee's calendar and are visible in the Bitrix24 web interface. To have all events written to a single section, pass the `sectionId` of an existing section — its ID can be taken from the [`GET /v1/calendar-events`](./list.md) response.

## See also

- [Event fields](./fields.md)
- [Update event](./update.md)
- [Delete event](./delete.md)
- [List events](./list.md)
