192 lines
8.8 KiB
JSON
192 lines
8.8 KiB
JSON
{
|
|
"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" } } } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|