Launch27 Account Settings API

Read a client account's configuration - branding, currency, country and states, enabled feature flags (multi-location, gift cards, tips, sales tax, SMS reminders, mobile app, etc.), locale/date preferences, accepted payment methods, and the default location. Some fields (Stripe public key, team permissions, alerts, admin id, and a wss:// pubsub notification URL) are only present for authenticated staff/team requests.

OpenAPI Specification

launch27-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Launch27 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.
tags:
  - name: Authentication
    description: Login and JWT bearer token issuance.
  - name: Account
    description: Account/tenant settings and configuration.
  - name: Booking Helpers
    description: Supporting data for building and pricing a booking form.
  - name: Policy
    description: Booking, reschedule, cancellation, and location policies.
  - name: Guest Booking
    description: Booking creation for non-logged-in customers.
  - name: Customer Bookings
    description: Authenticated customer-portal booking CRUD.
security:
  - bearerAuth: []
paths:
  /login:
    post:
      operationId: login
      tags:
        - Authentication
      summary: Authenticate and obtain a JWT bearer token
      security: []
      description: >-
        Authenticates a customer or staff user. Returns 401 on failure, 403
        if the account is locked (5 invalid attempts within 1 minute locks
        the account for 5 minutes) or a 2FA token is required, 422 on schema
        errors.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        '200':
          description: Authenticated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Account locked out, or OTP token required.
        '422':
          $ref: '#/components/responses/ValidationError'
  /settings:
    get:
      operationId: getSettings
      tags:
        - Account
      summary: Get account settings
      security:
        - bearerAuth: []
        - {}
      description: >-
        Returns account configuration. Response content varies by
        authentication state, user type, and feature availability - some
        fields (stripe_public_key, team_permissions, alerts, admin_id,
        pubsub_url, quickbooks_authorized) require authentication and/or a
        staff/team user type.
      responses:
        '200':
          description: Account settings.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Settings'
  /booking/form:
    get:
      operationId: getBookingForm
      tags:
        - Booking Helpers
      summary: Get booking form setup
      security: []
      parameters:
        - name: type
          in: query
          required: false
          description: >-
            Booking form type (requires features.new_booking_form_widget).
          schema:
            type: string
            enum: [cleaning, auto, lawn, carpet]
      responses:
        '200':
          description: Booking form headings, system fields, paragraphs, and appearance settings.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /booking/services:
    get:
      operationId: getBookingServices
      tags:
        - Booking Helpers
      summary: Get services available for booking
      security:
        - bearerAuth: []
        - {}
      parameters:
        - $ref: '#/components/parameters/BookingUuid'
        - $ref: '#/components/parameters/LocationId'
      responses:
        '200':
          description: List of available services.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Service'
  /booking/spots:
    post:
      operationId: getBookingSpots
      tags:
        - Booking Helpers
      summary: Get available spots for booking
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SpotsRequest'
      responses:
        '200':
          description: Available spots by date (or grid + days if grid=true).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /booking/location:
    post:
      operationId: getBookingLocation
      tags:
        - Booking Helpers
      summary: Resolve location for a booking address
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LocationRequest'
      responses:
        '200':
          description: Resolved location.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Location'
  /booking/frequencies:
    get:
      operationId: getBookingFrequencies
      tags:
        - Booking Helpers
      summary: Get frequencies available for booking
      security:
        - bearerAuth: []
        - {}
      parameters:
        - $ref: '#/components/parameters/BookingUuid'
        - $ref: '#/components/parameters/LocationId'
      responses:
        '200':
          description: List of configured frequencies.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Frequency'
  /booking/frequencies/{id}/next:
    post:
      operationId: getNextBookingDateForFrequency
      tags:
        - Booking Helpers
      summary: Get next recurring booking date for a frequency
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: Frequency unique ID.
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [date]
              properties:
                date:
                  type: string
                  description: 'YYYY-MM-DDTHH:MM:SS'
      responses:
        '200':
          description: Next recurring date.
          content:
            application/json:
              schema:
                type: object
                properties:
                  date:
                    type: string
                    format: date-time
        '422':
          description: Schema error, or frequency is not recurring.
  /booking/custom_fields:
    get:
      operationId: getBookingCustomFields
      tags:
        - Booking Helpers
      summary: Get custom fields for booking
      security:
        - bearerAuth: []
        - {}
      parameters:
        - $ref: '#/components/parameters/BookingUuid'
      responses:
        '200':
          description: List of custom fields.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CustomField'
  /booking/estimate_price:
    post:
      operationId: estimateBookingPrice
      tags:
        - Booking Helpers
      summary: Estimate price for a booking
      security:
        - bearerAuth: []
        - {}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PriceEstimateRequest'
      responses:
        '200':
          description: Price estimate.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceEstimate'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Customer has no access to booking.
  /policy/booking:
    get:
      operationId: getNewBookingPolicy
      tags:
        - Policy
      summary: Get new booking policy
      security: []
      responses:
        '200':
          description: New booking lead-time policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LeadTimePolicy'
  /policy/reschedule:
    get:
      operationId: getRescheduleBookingPolicy
      tags:
        - Policy
      summary: Get booking reschedule policy
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Reschedule lead-time policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LeadTimePolicy'
  /policy/cancellation:
    get:
      operationId: getCancellationPolicy
      tags:
        - Policy
      summary: Get booking cancellation policy
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Cancellation fee/percent and reason-required policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancellationPolicy'
  /policy/location:
    get:
      operationId: getLocationPolicy
      tags:
        - Policy
      summary: Get "prevent booking if location not found" policy
      security: []
      responses:
        '200':
          description: Location policy.
          content:
            application/json:
              schema:
                type: object
                properties:
                  prevent_booking:
                    type: boolean
                  prevent_booking_text:
                    type: string
  /booking:
    post:
      operationId: createGuestBooking
      tags:
        - Guest Booking
      summary: Create a new booking as a non-logged-in customer
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GuestBookingRequest'
      responses:
        '200':
          description: Booking created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BookingCreatedResponse'
        '422':
          $ref: '#/components/responses/ValidationError'
  /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:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        JWT returned as `bearer` in the Login response. Sent as
        `Authorization: Bearer <JWT>`. A legacy `email:token` form
        (Authorization: email:token) existed but was retired March 1, 2023.
  parameters:
    BookingUuid:
      name: booking_uuid
      in: query
      required: false
      description: Booking digest; required (and requires auth) when requesting for an existing booking.
      schema:
        type: string
    LocationId:
      name: location_id
      in: query
      required: false
      description: Unique ID of location; default location used if omitted.
      schema:
        type: integer
  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
  schemas:
    LoginRequest:
      type: object
      required: [email, password]
      properties:
        email:
          type: string
          format: email
        password:
          type: string
        token:
          type: string
          description: 6-digit 2FA token, if enabled.
    LoginResponse:
      type: object
      properties:
        id:
          type: integer
        email:
          type: string
        type:
          type: string
          example: 'Tenant::Customer'
        first_name:
          type: string
        last_name:
          type: string
        bearer:
          type: string
          description: JWT bearer token.
    Settings:
      type: object
      description: See https://bitbucket.org/awoo23/api-2.0/wiki/Get_settings for full attribute documentation.
      additionalProperties: true
      properties:
        logo:
          type: string
          format: uri
        color:
          type: string
        name:
          type: string
        status:
          type: string
          enum: [trial, active, frozen, sleep]
        sandbox:
          type: boolean
        setup_complete:
          type: boolean
        timezone:
          type: string
        currency:
          type: object
          properties:
            code:
              type: string
            symbol:
              type: string
        country:
          type: object
          additionalProperties: true
        features:
          type: object
          additionalProperties: true
        payment_methods:
          type: object
          additionalProperties: true
        default_location:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
        pubsub_url:
          type: string
          description: >-
            wss:// notification subscription URL, present only when
            authenticated. Example:
            wss://pubsub.l27.co/v1/subscribe?channel=3yicbolh5nv4s8wv
    Service:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        price:
          type: number
        commercial:
          type: boolean
        discount_by_frequency:
          type: boolean
        discount_by_code:
          type: boolean
        hourly:
          type: object
          nullable: true
          additionalProperties: true
        extras:
          type: array
          items:
            $ref: '#/components/schemas/Extra'
        pricing_parameters:
          type: array
          items:
            $ref: '#/components/schemas/PricingParameter'
    Extra:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        price:
          type: number
        quantity_based:
          type: boolean
        recurring:
          type: boolean
        discount_by_frequency:
          type: boolean
        discount_by_code:
          type: boolean
    PricingParameter:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        price:
          type: number
        quantity_minimum:
          type: integer
        quantity_maximum:
          type: integer
    SpotsRequest:
      type: object
      required: [date, days, mode]
      properties:
        date:
          type: string
          format: date
        days:
          type: integer
          minimum: 1
          maximum: 7
        mode:
          type: string
          enum: [new, reschedule]
        location_id:
          type: integer
          nullable: true
        grid:
          type: boolean
          nullable: true
    LocationRequest:
      type: object
      properties:
        address:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        state:
          type: string
          nullable: true
        zip:
          type: string
          nullable: true
    Location:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
    Frequency:
      type: object
      properties:
        id:
          type: integer
        interval:
          type: string
          description: "'o' = one time; otherwise a recurring interval pattern like 1w, 2m15d."
        name:
          type: string
        percent:
          type: number
        amount:
          type: number
        exclude_first:
          type: boolean
        default:
          type: boolean
    CustomField:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        label:
          type: string
        control_type:
          type: string
          enum: [single_line, multi_line, radio_buttons, checkboxes, drop_down, plain_text, date, datetime, checkbox]
        value_required:
          type: boolean
        visible:
          type: boolean
        ordering:
          type: integer
        default_value:
          type: string
        options:
          type: array
          items:
            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
    PriceEstimateRequest:
      type: object
      required: [service_date, frequency_id, services]
      properties:
        email:
          type: string
          format: email
        booking_uuid:
          type: string
          nullable: true
        original_booking_id:
          type: integer
          nullable: true
        service_date:
          type: string
        location_id:
          type: integer
          nullable: true
        frequency_id:
          type: integer
        services:
          type: array
          items:
            $ref: '#/components/schemas/ServiceSelection'
        discount_code:
          type: string
          nullable: true
        tip:
          type: number
          nullable: true
        tip_recurring:
          type: boolean
          nullable: true
        price_adjustment:
          type: number
          nullable: true
          description: Staff-only.
        final_price:
          type: number
          nullable: true
          description: Staff-only.
    PriceEstimate:
      type: object
      properties:
        services:
          type: number
        extras:
          type: number
        discount_amount:
          type: number
        discount_message:
          type: string
        giftcard_amount:
          type: number
        price_adjustment:
          type: number
        tax:
          type: object
          additionalProperties: true
        tip:
          type: number
        total:
          type: number
        next_total:
          type: number
        duration:
          type: integer
        price_for_frequency:
          type: number
        price_for_discount_by_code:
          type: number
        price_recurring_for_frequency:
          type: number
    LeadTimePolicy:
      type: object
      properties:
        custom:
          type: boolean
        unit:
          type: string
          enum: [hour, day]
        quantity:
          type: integer
    CancellationPolicy:
      type: object
      properties:
        custom:
          type: boolean
        unit:
          type: string
          enum: [hour, day]
        quantity:
          type: integer
        late_cancellation_fee:
          type: number
        late_cancellation_percent:
          type: number
        cancellation_reason_on:
          type: boolean
    GuestBookingRequest:
      type: object
      required: [user, address, frequency_id, service_date, arrival_window, services, payment_method]
      properties:
        location_id:
          type: integer
          nullable: true
        user:
          type: object
          required: [email, first_name, last_name]
          properties:
            email:
              type: string
              format: email
            first_name:
              type: string
            last_name:
              type: string
            company_name:
              type: string
              nullable: true
        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
          minimum: 0
          maximum: 1440
        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]
        stripe_token:
          type: string
          nullable: true
          description: Required if payment_method=stripe. Generated via Stripe.js using stripe_public_key from Get Settings.
        customer_notes:
          type: string
          nullable: true
        custom_fields:
          type: array
          nullable: true
          items:
            type: object
            additionalProperties: true
    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
    UpdateCustomerBookingRequest:
      allOf:
        - $ref: '#/components/schemas/CustomerBookingRequest'
        - type: object
          properties:
            create_next_recurring:
              type: object
              nullable: true
              required: [service_date]
              properties:
                service_date:
                  type: string
    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
    BookingCreatedResponse:
      type: object
      properties:
        id:
          type: integer
        ga_transaction:
          type: object
          additionalProperties: true
        ga_item:
          type: object
          additionalProperties: true
    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