openapi: 3.0.3 info: title: Launch27 Account Customer Bookings API description: 'Unofficial-but-real, actively used REST API for Launch27, a booking and scheduling platform for cleaning service businesses. Documented in a public Bitbucket wiki (https://bitbucket.org/awoo23/api-2.0/wiki/Home) linked from the launch27.com site footer, rather than in Launch27''s first-party docs.launch27.com knowledge base. The API is multi-tenant: every client account has its own subdomain. This document models the current v2.1 surface (the deprecated v2.0 surface is not modeled). Not every endpoint mentioned in the wiki is represented here in full schema detail; refer to the wiki pages linked per operation for complete field-by-field documentation.' version: '2.1' contact: name: API Evangelist email: kin@apievangelist.com servers: - url: https://{tenant}.launch27.com/v1 description: Production (per-tenant subdomain) variables: tenant: default: acme description: Launch27 client account subdomain. - url: https://{tenant}.l27.co/v1 description: Testing/sandbox (per-tenant subdomain) variables: tenant: default: acme-sandbox description: Launch27 sandbox account subdomain. security: - bearerAuth: [] tags: - name: Customer Bookings description: Authenticated customer-portal booking CRUD. paths: /customer/bookings: get: operationId: listCustomerBookings tags: - Customer Bookings summary: List active bookings for the logged-in customer parameters: - name: from in: query schema: type: string format: date - name: to in: query schema: type: string format: date - name: query in: query description: Free-text search across address, city, phone. schema: type: string - name: options in: query description: Comma-separated; completed, not_completed, with_feedback, without_feedback. schema: type: string - name: limit in: query schema: type: integer - name: offset in: query schema: type: integer - name: sort in: query schema: type: string enum: - asc - desc default: desc responses: '200': description: List of bookings. content: application/json: schema: type: array items: $ref: '#/components/schemas/Booking' '401': $ref: '#/components/responses/Unauthorized' '403': description: User is not a customer user. post: operationId: createCustomerBooking tags: - Customer Bookings summary: Create a new booking as the logged-in customer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CustomerBookingRequest' responses: '200': description: Booking created. content: application/json: schema: $ref: '#/components/schemas/BookingCreatedResponse' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /customer/bookings/count: get: operationId: countCustomerBookings tags: - Customer Bookings summary: Count active bookings for the logged-in customer responses: '200': description: Booking count. content: application/json: schema: type: object properties: count: type: integer '401': $ref: '#/components/responses/Unauthorized' '403': description: User is not a customer user. /customer/bookings/{id}: parameters: - name: id in: path required: true description: Booking unique ID. schema: type: integer get: operationId: getCustomerBooking tags: - Customer Bookings summary: Get a single booking's details responses: '200': description: Booking detail. content: application/json: schema: $ref: '#/components/schemas/Booking' '401': $ref: '#/components/responses/Unauthorized' '403': description: Customer has no access to booking. put: operationId: updateCustomerBooking tags: - Customer Bookings summary: Update or reschedule an existing booking requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateCustomerBookingRequest' responses: '200': description: Updated booking. content: application/json: schema: $ref: '#/components/schemas/Booking' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /customer/bookings/{id}/cancel: post: operationId: cancelCustomerBooking tags: - Customer Bookings summary: Cancel an existing booking parameters: - name: id in: path required: true description: Booking unique ID. schema: type: integer requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CancelBookingRequest' responses: '200': description: Booking cancelled. '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' components: schemas: CustomerBookingRequest: type: object required: - address - frequency_id - service_date - arrival_window - services - payment_method properties: location_id: type: integer nullable: true original_booking_id: type: integer nullable: true description: '"Book This Again" reference to a prior booking owned by the customer.' address: type: string city: type: string nullable: true state: type: string nullable: true zip: type: string nullable: true phone: type: string nullable: true sms_notifications: type: boolean nullable: true frequency_id: type: integer service_date: type: string arrival_window: type: integer services: type: array minItems: 1 items: $ref: '#/components/schemas/ServiceSelection' discount_code: type: string nullable: true tip: type: number nullable: true tip_recurring: type: boolean nullable: true payment_method: type: string enum: - stripe - paypal - cash - check customer_notes: type: string nullable: true custom_fields: type: array nullable: true items: type: object additionalProperties: true BookingCreatedResponse: type: object properties: id: type: integer ga_transaction: type: object additionalProperties: true ga_item: type: object additionalProperties: true ServiceSelection: type: object required: - id properties: id: type: integer hourly: type: object nullable: true properties: quantity: type: integer minutes: type: integer extras: type: array nullable: true items: type: object required: - id - quantity properties: id: type: integer quantity: type: integer recurring: type: boolean nullable: true pricing_parameters: type: array nullable: true items: type: object required: - id - quantity properties: id: type: integer quantity: type: integer UpdateCustomerBookingRequest: allOf: - $ref: '#/components/schemas/CustomerBookingRequest' - type: object properties: create_next_recurring: type: object nullable: true required: - service_date properties: service_date: type: string Booking: type: object description: See https://bitbucket.org/awoo23/api-2.0/wiki/Get_booking_for_customer for full attribute documentation. additionalProperties: true properties: id: type: integer digest: type: string service_date: type: string format: date-time arrival_window: type: integer address: type: object additionalProperties: true active: type: boolean completed: type: boolean name: type: string email: type: string phone: type: string frequency: type: object additionalProperties: true payment_method_info: type: object additionalProperties: true services: type: array items: type: object additionalProperties: true summary: type: object additionalProperties: true actions: type: object additionalProperties: true CancelBookingRequest: type: object properties: confirmed_late: type: boolean confirmed_fee: type: number nullable: true confirmed_recurring: type: object nullable: true properties: cancel_future: type: boolean reason: type: string nullable: true responses: Unauthorized: description: Missing/invalid Authorization header, or invalid credentials. ValidationError: description: JSON schema or data validation error. content: application/json: schema: type: object additionalProperties: true securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: 'JWT returned as `bearer` in the Login response. Sent as `Authorization: Bearer `. A legacy `email:token` form (Authorization: email:token) existed but was retired March 1, 2023.'