Skip to the documentation
API

Create a booking page

Makes a page that takes bookings at once. Only `name` is required.

POST/booking-pages

Runs the real call on your workspace.

POST /booking-pages

Makes a page that takes bookings at once. Only name is required.

Example

Needs calendar:write and emails:send. Left to its defaults, a page is open on weekdays from 09:00 to 17:00, offers 30 minute meetings, asks for four hours of notice, and sends from the first address the person may send from.

curl
curl -X POST "$OE/booking-pages" -H "$AUTH" -H 'content-type: application/json' -d '{  "name": "Intro call",  "timezone": "Europe/Berlin",  "config": {    "description": "A first chat about your project.",    "location": { "kind": "video", "value": "https://meet.example.com/hana" },    "rules": { "bufferAfterMinutes": 15 }  }}'
Response
{  "object": "booking_page",  "id": "bkp_5c1e9a7b3d2f48e6a0b4c7d1",  "slug": "intro-call",  "name": "Intro call",  "status": "active",  "url": "https://openemail.uk/book/intro-call",  "problem": null,  "config": {    "description": "A first chat about your project.",    "hostName": "Hana Sato",    "durations": [30],    "location": { "kind": "video", "value": "https://meet.example.com/hana" },    "availability": {      "timezone": "Europe/Berlin",      "weekly": [        [],        [{ "start": 540, "end": 1020 }],        [{ "start": 540, "end": 1020 }],        [{ "start": 540, "end": 1020 }],        [{ "start": 540, "end": 1020 }],        [{ "start": 540, "end": 1020 }],        []      ],      "overrides": [{ "date": "2026-12-24", "ranges": [] }]    },    "rules": {      "noticeMinutes": 240,      "horizonDays": 60,      "intervalMinutes": null,      "bufferBeforeMinutes": 0,      "bufferAfterMinutes": 15,      "dailyLimit": null    },    "approval": false,    "fromEmail": "[email protected]",    "notifyHost": true,    "questions": [      { "id": "notes", "kind": "long-text", "label": "Anything we should know?", "required": false, "options": [] }    ],    "confirmation": "",    "redirectUrl": "",    "appearance": {      "accent": "#2563eb",      "theme": "auto",      "showAvatar": true,      "background": "default",      "fonts": { "primary": null, "secondary": null },      "backgroundImage": null    },    "guestChanges": { "cancel": true, "reschedule": true, "cutoffMinutes": 120 },    "busy": { "addresses": null, "subscriptions": true, "outOfOffice": true },    "seo": { "title": "", "description": "", "indexable": false },    "extraGuests": 0  },  "counts": { "upcoming": 3, "pending": 0 },  "away": [    { "address": "[email protected]", "startsAt": "2026-12-22T00:00:00.000Z", "endsAt": "2027-01-02T00:00:00.000Z" }  ],  "createdAt": "2026-10-13T07:00:05.870Z",  "updatedAt": "2026-10-13T07:00:05.870Z"}

Anything in config replaces the default for that setting. Inside location, availability, rules, appearance, guestChanges, busy and seo each field is set on its own, so the example changes one rule and keeps the rest.

Left out, slug is made from the name. A slug another page uses answers 409 booking_link_taken.

A link with characters it may not have, a sender the person may not send from, or a video meeting with no link answers 422 invalid_booking_page, and the message says which.

Reference