{ "paths": { "/calendars/{id}/booking-link": { "post": { "tags": ["Booking"], "summary": "Create a booking link", "description": "Creates a public booking link for a calendar with configurable duration, buffer time, working hours, and timezone. Only the calendar owner can create booking links. Requires `booking:write` scope.", "operationId": "createBookingLink", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Calendar ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["duration_minutes", "timezone", "working_hours"], "properties": { "duration_minutes": { "type": "integer", "minimum": 5, "example": 30 }, "buffer_minutes": { "type": "integer", "minimum": 0, "default": 0, "example": 0 }, "timezone": { "type": "string", "example": "America/Asuncion" }, "working_hours": { "type": "object", "description": "Working hour windows per day of week", "properties": { "mon": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "tue": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "wed": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "thu": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "fri": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "sat": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } }, "sun": { "type": "array", "items": { "$ref": "#/components/schemas/WorkingHourSlot" } } }, "example": { "mon": [{ "start": "09:00", "end": "17:00" }], "tue": [{ "start": "09:00", "end": "17:00" }], "wed": [{ "start": "09:00", "end": "17:00" }], "thu": [{ "start": "09:00", "end": "17:00" }], "fri": [{ "start": "09:00", "end": "17:00" }], "sat": [], "sun": [] } }, "active": { "type": "boolean", "default": true } } } } } }, "responses": { "200": { "description": "Booking link created", "content": { "application/json": { "schema": { "type": "object", "required": ["token", "settings"], "properties": { "token": { "type": "string" }, "public_url": { "type": "string", "format": "uri", "example": "https://app.example.com/booking/abc123" }, "settings": { "type": "object", "properties": { "duration_minutes": { "type": "integer" }, "buffer_minutes": { "type": "integer" }, "timezone": { "type": "string" }, "working_hours": { "type": "object" }, "active": { "type": "boolean" } } } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Only owner can create booking links", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Calendar not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/booking/{token}/availability": { "get": { "tags": ["Booking"], "summary": "Get public booking availability", "description": "Returns available time slots for a public booking link within a date range. No authentication required. Computes available slots by subtracting busy blocks and applying buffer time to the working hour windows.", "operationId": "getBookingAvailability", "security": [], "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Booking link token" }, { "name": "start", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" }, "description": "Range start (RFC3339)" }, { "name": "end", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" }, "description": "Range end (RFC3339)" } ], "responses": { "200": { "description": "Available booking slots", "content": { "application/json": { "schema": { "type": "object", "required": ["token", "timezone", "duration_minutes", "slots"], "properties": { "token": { "type": "string" }, "timezone": { "type": "string" }, "duration_minutes": { "type": "integer" }, "slots": { "type": "array", "items": { "$ref": "#/components/schemas/TimeSlot" } } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Booking link not found or inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/booking/{token}/reserve": { "post": { "tags": ["Booking"], "summary": "Reserve a booking slot", "description": "Reserves a time slot on a public booking link. Creates an event on the calendar. Uses a database transaction with row locking to prevent double-booking. No authentication required.", "operationId": "reserveBookingSlot", "security": [], "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Booking link token" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name", "email", "slot_start", "slot_end"], "properties": { "name": { "type": "string", "example": "Visitor Name" }, "email": { "type": "string", "format": "email", "example": "visitor@example.com" }, "slot_start": { "type": "string", "format": "date-time" }, "slot_end": { "type": "string", "format": "date-time" }, "notes": { "type": "string", "example": "Looking forward to the meeting" } } } } } }, "responses": { "200": { "description": "Booking confirmed", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "event"], "properties": { "ok": { "type": "boolean", "example": true }, "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Booking link not found or inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Slot no longer available (conflict)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } } }