Create an event
Creates an event and sends invitations to any attendees.
Permission
The key must be granted calendar.events.write
A key without it gets 403 insufficient_scope, with the missing permission named in details.
Listing an attendee sends them an invitation. To reschedule afterwards use PATCH rather than deleting and recreating: PATCH keeps the id and UID and raises the sequence, so their calendar updates the meeting in place instead of cancelling one and inviting them to another.
Path parameters
| Field | Type | Description |
|---|---|---|
calendar_id required |
string | The calendar to add it to. |
Request body
| Field | Type | Description |
|---|---|---|
summary required |
string | The title, as it appears in a calendar app. |
starts_at required |
RFC 3339 | In UTC. 2026-09-05T12:00:00Z is 3pm where the offset is +03:00. |
ends_at required |
RFC 3339 | Must be after starts_at. |
description |
string | |
location |
string | |
url |
string | Typically a meeting link. |
all_day |
boolean |
Stores dates without times.
Defaults to false
|
rrule |
string | An RFC 5545 recurrence rule, for example FREQ=WEEKLY;BYDAY=TU,TH. |
organizer |
string |
The address shown as organiser.
Defaults to you
|
attendees |
object[] | Who is invited. Listing anyone here sends them an invitation. Its fields are below. |
Each item in attendees
| Field | Type | Description |
|---|---|---|
email required |
string | The only required field on an attendee. |
display_name |
string | Shown instead of the address in a calendar app. |
role |
string |
Whether their presence is needed, optional, or informational.
REQ-PARTICIPANTOPT-PARTICIPANTNON-PARTICIPANTCHAIR
Defaults to REQ-PARTICIPANT
|
partstat |
string |
Their answer. Set it only when you already know it; otherwise leave it for them to give.
NEEDS-ACTIONACCEPTEDDECLINEDTENTATIVEDELEGATED
Defaults to NEEDS-ACTION
|
cutype |
string |
What kind of attendee this is.
INDIVIDUALGROUPRESOURCEROOM
Defaults to INDIVIDUAL
|
Request
curl https://api.veruapis.com/v1/calendars/:calendar_id/events \
-X POST \
-H "Authorization: Bearer vak_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"summary": "Meeting with Justina",
"starts_at": "2026-09-05T12:00:00Z",
"ends_at": "2026-09-05T13:00:00Z",
"attendees": [ { "email": "[email protected]", "role": "REQ-PARTICIPANT" } ]
}'
Idempotency-Key is required on every write. Retrying with the same key returns the original response rather than repeating the operation, so a timeout is something you retry rather than something you investigate.
Response
Answers 201.
{
"data": {
"id": "fa9a0631-da8e-4210-8a92-d6f880986294",
"uid": "f8405b1d-6201-46eb-9022-f203d036d575@verusuite",
"calendar_id": "1d81f1c3-4df0-42c8-b880-506e77333792",
"summary": "Meeting with Justina",
"starts_at": "2026-09-05T12:00:00Z",
"ends_at": "2026-09-05T13:00:00Z",
"sequence": 0,
"attendees": [ { "email": "[email protected]", "partstat": "NEEDS-ACTION", "rsvp_required": true } ]
},
"meta": { "request_id": "req_01j8z9...", "timestamp": "2026-09-02T10:00:00Z" }
}
Listing an attendee sends them an invitation. To reschedule afterwards use PATCH rather than delete-and-recreate: PATCH keeps the id and UID and bumps sequence, so their calendar updates the meeting in place instead of cancelling one and inviting them to another.
Every failure uses the same shape, with a stable string code you can branch on. See the error reference.
Related
- POST Create a calendar
- DELETE Delete a calendar
- DELETE Delete an event
- POST Find a time that works
- POST Query free/busy
- GET Get a calendar
- GET Get an event
- GET List events in a calendar
- GET List calendars
- GET List events
- POST Respond to an invitation
- PATCH Update a calendar
- PATCH Update an event