> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dialtu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Book an appointment

> Book one appointment.

Everything about the APPOINTMENT is explicit: the service, the professional,
the appointment type, both ends of the window, and the timezone they are
written in. Nothing is auto-assigned — an unmatched or ambiguous value is
refused, and the refusal names what would have been accepted.

Everything about the MESSAGING is not: whether a confirm-request or
reminders go out, and when, comes from the calendar's own Notifications
settings, so an appointment booked here behaves exactly like the same
appointment booked in the dashboard.

The customer is matched on their phone number and created if unknown.

**Availability is never a reason to fail here**: the appointment is booked
even if it falls outside declared working hours or overlaps another one. The
calling system owns the schedule.



## OpenAPI

````yaml POST /api/v2/public/calendar/events
openapi: 3.1.0
info:
  title: Dialtu Public API
  version: '2.0'
  description: >-
    Programmatic access to your Dialtu account: schedule AI voice calls, create
    contacts, push leads into Salesflow pipelines, book calendar appointments
    and read WhatsApp conversation history.


    Every request is authenticated with an API key created in the dashboard
    under **Settings → API Keys**, sent as `Authorization: Bearer pk_...`.
servers:
  - url: https://api.dialtu.com
    description: Production
  - url: https://api.stg.dialtu.com
    description: Staging
security:
  - ApiKeyBearer: []
tags:
  - name: Calls
    description: Schedule outbound AI voice calls.
  - name: Clients
    description: Create contacts in your account.
  - name: Salesflow
    description: Push leads into a pipeline through an API input node.
  - name: Salesflow pipelines
    description: Read a pipeline's stages and add, move or remove clients.
  - name: Calendar
    description: Check bookable capacity, book appointments and manage waiting lists.
  - name: WhatsApp
    description: Read-only conversation history and transcripts.
paths:
  /api/v2/public/calendar/events:
    post:
      tags:
        - Calendar
      summary: Book an appointment
      description: >-
        Book one appointment.


        Everything about the APPOINTMENT is explicit: the service, the
        professional,

        the appointment type, both ends of the window, and the timezone they are

        written in. Nothing is auto-assigned — an unmatched or ambiguous value
        is

        refused, and the refusal names what would have been accepted.


        Everything about the MESSAGING is not: whether a confirm-request or

        reminders go out, and when, comes from the calendar's own Notifications

        settings, so an appointment booked here behaves exactly like the same

        appointment booked in the dashboard.


        The customer is matched on their phone number and created if unknown.


        **Availability is never a reason to fail here**: the appointment is
        booked

        even if it falls outside declared working hours or overlaps another one.
        The

        calling system owns the schedule.
      operationId: createCalendarEvent
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicCreateCalendarEventSchema'
        required: true
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCalendarEventResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCalendarErrorResponse'
        '401':
          description: Missing, malformed or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetailErrorResponse'
              examples:
                missing_header:
                  summary: No Authorization header
                  value:
                    detail: Unauthorized
                invalid_key:
                  summary: Unknown or revoked key
                  value:
                    detail: Invalid or expired API key. Please check your credentials.
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCalendarErrorResponse'
        '422':
          description: >-
            Unprocessable Content — or the request did not match the documented
            schema.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/PublicCalendarErrorResponse'
                  - $ref: '#/components/schemas/RequestValidationError'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCalendarErrorResponse'
      security:
        - ApiKeyBearer: []
components:
  schemas:
    PublicCreateCalendarEventSchema:
      description: Body of *Book an appointment*.
      examples:
        - client:
            first_name: Jane
            last_name: Roe
            phone: '+573001112233'
          end_at: '2026-09-15T14:30:00'
          event_type_name: In-Person
          notes: Booked from the website form
          professional_name: Ana Gómez
          service_name: Consulta Médica
          start_at: '2026-09-15T14:00:00'
          timezone: America/Bogota
      properties:
        client:
          $ref: '#/components/schemas/PublicBookingClientSchema'
          description: The customer the appointment is for.
        start_at:
          anyOf:
            - format: date-time
              type: string
            - type: 'null'
          description: >-
            Local start time in `timezone`, e.g. 2026-09-15T14:00:00. An
            explicit UTC offset is accepted and then wins over `timezone`.
          title: Start At
        end_at:
          anyOf:
            - format: date-time
              type: string
            - type: 'null'
          description: >-
            Local end time in `timezone`. Required — it is never derived from
            the service's default duration.
          title: End At
        timezone:
          anyOf:
            - maxLength: 64
              type: string
            - type: 'null'
          description: IANA zone name for start_at/end_at, e.g. 'America/Bogota'.
          title: Timezone
        service_id:
          anyOf:
            - type: integer
            - type: 'null'
          description: >-
            Service ID from *List bookable services*. One of
            `service_id`/`service_name` is required.
          title: Service Id
        service_name:
          anyOf:
            - maxLength: 255
              type: string
            - type: 'null'
          description: Alternative to service_id. One of the two is required.
          title: Service Name
        professional_id:
          anyOf:
            - type: integer
            - type: 'null'
          description: Professional ID; must be an active member of the service.
          title: Professional Id
        professional_name:
          anyOf:
            - maxLength: 255
              type: string
            - type: 'null'
          description: >-
            Alternative to professional_id. One of the two is required — this
            API never picks the professional for you.
          title: Professional Name
        event_type_id:
          anyOf:
            - type: integer
            - type: 'null'
          description: Appointment type ID; must be active and offered by the service.
          title: Event Type Id
        event_type_name:
          anyOf:
            - maxLength: 255
              type: string
            - type: 'null'
          description: Alternative to event_type_id. One of the two is required.
          title: Event Type Name
        notes:
          anyOf:
            - maxLength: 2000
              type: string
            - type: 'null'
          description: Free text shown to the team in Dialtu.
          title: Notes
      required:
        - client
      title: PublicCreateCalendarEventSchema
      type: object
    PublicCalendarEventResponse:
      description: Response of *Book an appointment*.
      properties:
        status:
          default: success
          description: Always `success`.
          title: Status
          type: string
        data:
          $ref: '#/components/schemas/PublicCalendarEventSchema'
          description: The booked appointment.
        client_id:
          description: The customer's client ID.
          title: Client Id
          type: integer
        client_created:
          description: >-
            `true` when this request created the customer, `false` when it
            matched an existing one.
          title: Client Created
          type: boolean
      required:
        - data
        - client_id
        - client_created
      title: PublicCalendarEventResponse
      type: object
    PublicCalendarErrorResponse:
      description: Error envelope shared by every public calendar endpoint.
      properties:
        status:
          const: error
          default: error
          description: Always `error`.
          title: Status
          type: string
        error_code:
          description: Machine-readable error code; branch on this, never on `message`.
          title: Error Code
          type: string
        message:
          description: Human-readable explanation.
          title: Message
          type: string
        details:
          anyOf:
            - {}
            - type: 'null'
          description: Extra context, e.g. `valid_service_names` or the offending `field`.
          title: Details
      required:
        - error_code
        - message
      title: PublicCalendarErrorResponse
      type: object
    DetailErrorResponse:
      description: 'Plain error body: `{"detail": "..."}`. No `error_code` is included.'
      properties:
        detail:
          description: Human-readable reason for the failure.
          title: Detail
          type: string
      required:
        - detail
      title: DetailErrorResponse
      type: object
    RequestValidationError:
      title: RequestValidationError
      type: object
      description: >-
        Returned when the request body, query string or path could not be parsed
        against the documented schema. Fix the listed fields and retry.
      properties:
        detail:
          type: array
          title: Detail
          description: One entry per invalid field.
          items:
            $ref: '#/components/schemas/RequestValidationErrorItem'
      required:
        - detail
    PublicBookingClientSchema:
      description: >-
        The customer the appointment is for.


        Found on ``phone`` (country-code tolerant, so ``+573001112233`` finds a

        customer stored from WhatsApp as ``3001112233``/``57``); created only
        when

        nothing matches.


        THE PHONE IS THE ONLY ALWAYS-REQUIRED FIELD. A name is required only on
        the

        create path — booking a customer the account already has needs nothing
        but

        their number, because the account already knows what to call them. When
        the

        number IS new, one of first/last is required and is never invented from
        the

        number: an appointment is a promise to contact someone.
      properties:
        first_name:
          anyOf:
            - maxLength: 150
              type: string
            - type: 'null'
          description: >-
            Given name. Required (one of first/last) only when the phone number
            is new to your account.
          title: First Name
        last_name:
          anyOf:
            - maxLength: 150
              type: string
            - type: 'null'
          description: Family name. See `first_name`.
          title: Last Name
        phone:
          anyOf:
            - maxLength: 32
              type: string
            - type: 'null'
          description: E.164, including the country code. Always required.
          title: Phone
        email:
          anyOf:
            - maxLength: 254
              type: string
            - type: 'null'
          description: >-
            Email address; only stored when the client is created by this
            request.
          title: Email
      title: PublicBookingClientSchema
      type: object
    PublicCalendarEventSchema:
      description: >-
        The booked appointment, echoed back.


        Mirrors ``CalendarEventDTO`` — the same read model the dashboard renders
        —

        so the two views of an appointment can never drift apart.
      properties:
        id:
          description: Appointment ID. Store it.
          title: Id
          type: integer
        start_at:
          description: Start instant, ISO 8601 UTC (`...Z`).
          title: Start At
          type: string
        end_at:
          description: End instant, ISO 8601 UTC (`...Z`).
          title: End At
          type: string
        status:
          description: Appointment status, e.g. `booked`.
          title: Status
          type: string
        source:
          description: Where the booking came from; `api` for this endpoint.
          title: Source
          type: string
        confirmation_status:
          description: Customer confirmation state, e.g. `pending` or `confirmed`.
          title: Confirmation Status
          type: string
        client:
          additionalProperties: true
          description: '`{id, name, phone}` of the customer.'
          title: Client
          type: object
        calendar_profile:
          additionalProperties: true
          description: '`{calendar_profile_id, name}` of the professional.'
          title: Calendar Profile
          type: object
        service:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          description: '`{id, name, color}` of the service.'
          title: Service
        event_type:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          description: '`{id, name, color}` of the appointment type.'
          title: Event Type
        custom_fields:
          additionalProperties: true
          description: Custom fields stored on the appointment.
          title: Custom Fields
          type: object
        created_at:
          description: Creation instant, ISO 8601 UTC.
          title: Created At
          type: string
      required:
        - id
        - start_at
        - end_at
        - status
        - source
        - confirmation_status
        - client
        - calendar_profile
        - custom_fields
        - created_at
      title: PublicCalendarEventSchema
      type: object
    RequestValidationErrorItem:
      title: RequestValidationErrorItem
      type: object
      properties:
        loc:
          type: array
          title: Loc
          description: >-
            Where the problem is: the first element is `body`, `query` or
            `path`, followed by the field path.
          items:
            anyOf:
              - type: string
              - type: integer
        msg:
          type: string
          title: Msg
          description: What is wrong with the value.
        type:
          type: string
          title: Type
          description: >-
            Machine-readable validation error type, e.g. `missing` or
            `int_parsing`.
      required:
        - loc
        - msg
        - type
  securitySchemes:
    ApiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: pk_...
      description: >-
        API key created in the dashboard under **Settings → API Keys**. Send it
        as `Authorization: Bearer pk_...`.

````