Files
Bookra/apps/backend/openapi/bookra.openapi.yaml
T
Tomas Dvorak 035ac8ddb5 first commit
2026-04-10 12:01:36 +02:00

499 lines
12 KiB
YAML

openapi: 3.0.3
info:
title: Bookra API
version: 0.1.0
description: >
Remote-first booking API for Bookra. The Go backend owns business rules,
scheduling logic, tenant isolation, and Stripe-backed plan enforcement.
servers:
- url: http://localhost:8080
tags:
- name: Health
- name: Public Booking
- name: Dashboard
- name: Tenant
- name: Billing
- name: Jobs
paths:
/healthz:
get:
tags: [Health]
operationId: getHealth
responses:
"200":
description: Service health
content:
application/json:
schema:
$ref: "#/components/schemas/HealthResponse"
/v1/meta/config:
get:
tags: [Health]
operationId: getPublicConfig
responses:
"200":
description: Public runtime configuration
content:
application/json:
schema:
$ref: "#/components/schemas/PublicConfig"
/v1/public/tenants/{tenantSlug}/availability:
get:
tags: [Public Booking]
operationId: getPublicAvailability
parameters:
- in: path
name: tenantSlug
required: true
schema:
type: string
responses:
"200":
description: Availability for a tenant booking page
content:
application/json:
schema:
$ref: "#/components/schemas/PublicAvailabilityResponse"
/v1/public/bookings:
post:
tags: [Public Booking]
operationId: createBooking
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateBookingRequest"
responses:
"201":
description: Booking created
content:
application/json:
schema:
$ref: "#/components/schemas/CreateBookingResponse"
/v1/dashboard/summary:
get:
tags: [Dashboard]
operationId: getDashboardSummary
security:
- bearerAuth: []
responses:
"200":
description: Tenant dashboard summary
content:
application/json:
schema:
$ref: "#/components/schemas/DashboardSummary"
"401":
description: Unauthorized
/v1/tenants/bootstrap:
get:
tags: [Tenant]
operationId: getTenantBootstrap
security:
- bearerAuth: []
responses:
"200":
description: Tenant bootstrap payload for the authenticated user
content:
application/json:
schema:
$ref: "#/components/schemas/TenantBootstrap"
"401":
description: Unauthorized
/v1/tenants/onboard:
post:
tags: [Tenant]
operationId: onboardTenant
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OnboardTenantRequest"
responses:
"201":
description: Tenant created for authenticated user
content:
application/json:
schema:
$ref: "#/components/schemas/TenantBootstrap"
"400":
description: Invalid request
"401":
description: Unauthorized
"409":
description: Conflict
/v1/billing/subscription:
get:
tags: [Billing]
operationId: getSubscriptionSnapshot
security:
- bearerAuth: []
responses:
"200":
description: Current subscription snapshot and entitlements
content:
application/json:
schema:
$ref: "#/components/schemas/SubscriptionSnapshot"
"401":
description: Unauthorized
/v1/billing/checkout:
post:
tags: [Billing]
operationId: createBillingCheckout
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CheckoutSessionRequest"
responses:
"200":
description: Hosted Stripe checkout session
content:
application/json:
schema:
$ref: "#/components/schemas/CheckoutSessionResponse"
"400":
description: Invalid request
"401":
description: Unauthorized
/v1/billing/refresh:
post:
tags: [Billing]
operationId: refreshSubscriptionSnapshot
security:
- bearerAuth: []
responses:
"200":
description: Refreshed snapshot
content:
application/json:
schema:
$ref: "#/components/schemas/SubscriptionSnapshot"
"401":
description: Unauthorized
/v1/webhooks/stripe:
post:
tags: [Billing]
operationId: handleStripeWebhook
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
"200":
description: Webhook accepted
/v1/internal/jobs/reminders/dispatch:
post:
tags: [Jobs]
operationId: dispatchReminderJobs
security:
- jobRunnerKey: []
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/DispatchReminderJobsRequest"
responses:
"200":
description: Reminder jobs dispatched
content:
application/json:
schema:
$ref: "#/components/schemas/DispatchReminderJobsResponse"
"401":
description: Unauthorized
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
jobRunnerKey:
type: apiKey
in: header
name: X-Bookra-Job-Key
schemas:
HealthResponse:
type: object
required: [status, environment]
properties:
status:
type: string
example: ok
environment:
type: string
example: staging
databaseConfigured:
type: boolean
PublicConfig:
type: object
required: [environment, neonAuthEnabled]
properties:
environment:
type: string
neonAuthEnabled:
type: boolean
apiUrl:
type: string
format: uri
TimeSlot:
type: object
required: [startsAt, endsAt, mode]
properties:
serviceId:
type: string
format: uuid
nullable: true
classSessionId:
type: string
format: uuid
nullable: true
staffId:
type: string
format: uuid
nullable: true
locationId:
type: string
format: uuid
nullable: true
startsAt:
type: string
format: date-time
endsAt:
type: string
format: date-time
mode:
type: string
enum: [appointment, class]
label:
type: string
remainingCapacity:
type: integer
nullable: true
PublicAvailabilityResponse:
type: object
required: [tenantSlug, timezone, locale, slots]
properties:
tenantSlug:
type: string
timezone:
type: string
locale:
type: string
enum: [cs, en]
slots:
type: array
items:
$ref: "#/components/schemas/TimeSlot"
CreateBookingRequest:
type: object
required: [tenantSlug, bookingMode, customerName, customerEmail, startsAt, endsAt]
properties:
tenantSlug:
type: string
bookingMode:
type: string
enum: [appointment, class]
serviceId:
type: string
format: uuid
classSessionId:
type: string
format: uuid
staffId:
type: string
format: uuid
locationId:
type: string
format: uuid
customerName:
type: string
customerEmail:
type: string
format: email
notes:
type: string
startsAt:
type: string
format: date-time
endsAt:
type: string
format: date-time
CreateBookingResponse:
type: object
required: [bookingId, reference, status]
properties:
bookingId:
type: string
format: uuid
reference:
type: string
status:
type: string
enum: [confirmed, waitlisted]
DashboardKPI:
type: object
required: [code, label, value]
properties:
code:
type: string
label:
type: string
value:
type: string
DashboardSummary:
type: object
required: [tenantName, locale, timezone, planCode, kpis]
properties:
tenantName:
type: string
locale:
type: string
timezone:
type: string
planCode:
type: string
kpis:
type: array
items:
$ref: "#/components/schemas/DashboardKPI"
TenantBootstrap:
type: object
required: [tenantId, tenantName, preset, locale, timezone, currentUser]
properties:
tenantId:
type: string
format: uuid
tenantName:
type: string
preset:
type: string
locale:
type: string
timezone:
type: string
planCode:
type: string
currentUser:
type: object
required: [subject, role]
properties:
subject:
type: string
email:
type: string
format: email
name:
type: string
role:
type: string
OnboardTenantRequest:
type: object
required: [name, slug, preset, locale, timezone]
properties:
name:
type: string
slug:
type: string
preset:
type: string
enum: [salon, clinic, massage, repair, studio]
locale:
type: string
enum: [cs, en]
timezone:
type: string
PlanEntitlements:
type: object
required: [maxLocations, maxStaff, smsAddonAvailable, advancedReporting]
properties:
maxLocations:
type: integer
maxStaff:
type: integer
smsAddonAvailable:
type: boolean
advancedReporting:
type: boolean
SubscriptionSnapshot:
type: object
required: [tenantId, customerId, subscriptionId, status, planCode, priceId, cancelAtPeriodEnd, entitlements]
properties:
tenantId:
type: string
format: uuid
customerId:
type: string
subscriptionId:
type: string
status:
type: string
planCode:
type: string
priceId:
type: string
cancelAtPeriodEnd:
type: boolean
currentPeriodStart:
type: string
format: date-time
nullable: true
currentPeriodEnd:
type: string
format: date-time
nullable: true
paymentMethodBrand:
type: string
paymentMethodLast4:
type: string
entitlements:
$ref: "#/components/schemas/PlanEntitlements"
lastSyncedAt:
type: string
format: date-time
nullable: true
checkoutUrlAvailable:
type: boolean
CheckoutSessionRequest:
type: object
required: [planCode]
properties:
planCode:
type: string
enum: [starter, growth, multi-location]
CheckoutSessionResponse:
type: object
required: [url]
properties:
url:
type: string
format: uri
DispatchReminderJobsRequest:
type: object
properties:
limit:
type: integer
minimum: 1
maximum: 200
DispatchReminderJobsResponse:
type: object
required: [processedCount, sentCount, failedCount]
properties:
processedCount:
type: integer
sentCount:
type: integer
failedCount:
type: integer