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

# Record attendance / check-in

> Marks a candidate as attended or not-attended when you already know
`bookingId` (e.g. you're processing bookings fetched from
`GET /bookings`). If your check-in point only has the candidate's
`attendanceCode` — the normal case for a desk or QR scan — use
`POST /attendance-codes/{attendanceCode}/check-in` instead, which resolves
the booking from the code itself. Both emit
`booking.attendance_updated` to your webhook endpoint. The booking
does not need to already be past its `scheduledStartAt` — you can
check a candidate in early.




## OpenAPI

````yaml /api-reference/openapi.yaml post /bookings/{bookingId}/attendance
openapi: 3.1.0
info:
  title: TapTalent Partner API
  version: 1.0.0
  summary: Partner API for jobs, candidates, pipelines, custom fields, and webhooks.
  description: >
    The TapTalent Partner API lets partner systems manage jobs, candidates,

    job-candidate relationships, hiring pipelines, and custom fields, and

    receive real-time event notifications via webhooks. All communication is

    JSON over HTTPS.


    ## Authentication


    Every request requires an API key sent as an HTTP bearer token:


    ```

    Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv

    ```


    Keys are prefixed `sk_live_` (production) or `sk_test_` (sandbox) followed

    by 22 base62 characters, are scoped to a company, and are generated from

    the TapTalent dashboard (Account Settings → Developers → API Key

    Management). Key management is dashboard-only and not available via this

    API.


    ## Response envelopes


    The API uses three envelope styles, by resource family:


    | Family | Success envelope |

    |---|---|

    | Jobs | Bare object (e.g. `{ "jobs": [...], "totalJobs": 45 }` or the job
    object itself) |

    | Candidates, Job Candidates, Pipelines, Custom Fields, Candidate
    Self-Scheduling | `{ "status": "success", "data": ... }` |

    | Candidates, Job Candidates, Pipelines, Custom Fields | `{ "status":
    "success", "data": ... }` |

    | Bulk resume upload and batch retrieval | `{ "success": true, "data": ...
    }` |


    Each operation in this specification models its family's actual envelope;

    no unified envelope is imposed.


    ## Pagination


    Pagination conventions vary by endpoint and are modeled as documented:


    | Endpoint | Page parameter | First page | Default page size | Page size
    rule |

    |---|---|---|---|---|

    | `GET /jobs` | `pageNumber` | 1 | 10 | one of 10, 20, 40, 80, 100 |

    | `GET /candidates/list` | `pageNumber` | **0** | 10 | one of 10, 20, 40,
    80, 100 |

    | `GET /candidates/batch/{batchId}` | `pageNumber` | 1 | 10 | one of 10, 20,
    40, 80, 100 |

    | `GET /job-candidates/job/{jobId}/candidates` | `page` | 1 | 20 | one of
    10, 20, 40, 80, 100 |

    | `GET /job-candidates/stage/{stageId}/candidates` | `page` | 1 | 20 | any
    value from 1 to 100 |

    | `GET /bookings` | `page` | 1 | 20 | any value from 1 to 100 |


    ## Errors


    Most errors use the canonical envelope:


    ```json

    {
      "error": {
        "code": "ERROR_CODE",
        "type": "error_type",
        "message": "Human-readable error message",
        "details": { "field": "Specific validation error message" }
      }
    }

    ```


    Authentication failures use flat shapes instead (`{"message": ...}`,

    `{"code": ..., "message": ...}` or `{"message": ..., "isApiKeyExists":

    false}`); see the shared 401 response. Rate limits are applied at the

    company level; numeric limits and the 429 response body are not yet

    published.


    ## Webhooks


    Event notifications are delivered as HTTP POST requests to a single

    company-level HTTPS endpoint configured in the dashboard. Deliveries carry

    the headers `X-Webhook-Event`, `X-Webhook-Timestamp`, and `X-Webhook-Key`

    (verify by plain equality against the key generated in the dashboard;

    HMAC signatures are not yet available). Endpoints must respond with a 2xx

    status within 5 seconds; failed deliveries are retried at 200 ms, 400 ms,

    and 800 ms before being marked failed. See the `webhooks` section of this

    document for every event payload.


    ## Conventions used in this specification


    - `x-inferred: true` marks schemas or responses whose shape is inferred
      from related endpoints because the source documentation does not include
      an example; verify against the sandbox before relying on exact field
      names.
    - `x-known-quirk` marks fields whose wire format deviates from the API's
      prevailing conventions (for example an epoch timestamp where other
      endpoints return ISO 8601 strings).
    - Where the published documentation shows placeholder string identifiers
      (for example `"pipelineId_1"` or `"companyId_1"`), this specification
      models the underlying integer identifier types used by the API and notes
      the resolution on the affected field.
  contact:
    name: TapTalent Support
    email: support@taptalent.ai
    url: https://docs.taptalent.io
  license:
    name: Proprietary
    url: https://taptalent.ai
servers:
  - url: https://partner-api.taptalent.io/v1/partner
    description: Production (use `sk_live_` keys)
  - url: https://sandbox.partner-api.taptalent.io/v1/partner
    description: Sandbox / staging (use `sk_test_` keys)
security:
  - bearerAuth: []
tags:
  - name: Jobs
    description: Create, read, update, and list jobs.
  - name: Candidates
    description: >-
      Create and retrieve candidates, upload resumes in bulk, and fetch
      candidates by batch or id list.
  - name: Job Candidates
    description: >-
      Manage the relationship between candidates and jobs, including stage
      placement and per-job resume ingestion.
  - name: Pipelines
    description: Manage hiring pipelines and their stages.
  - name: Custom Fields
    description: Define custom field templates for candidates and jobs.
  - name: Custom Field Values
    description: Read and write custom field values attached to candidates and jobs.
  - name: Candidate Self-Scheduling
    description: |
      Read booking schedules and their availability, generate candidate
      scheduling links, and read, reschedule, cancel, and record
      attendance for the bookings candidates make on them.
  - name: Webhooks
    description: >-
      Event notifications delivered to your configured webhook endpoint. See the
      top-level `webhooks` section for payloads.
paths:
  /bookings/{bookingId}/attendance:
    post:
      tags:
        - Candidate Self-Scheduling
      summary: Record attendance / check-in
      description: >
        Marks a candidate as attended or not-attended when you already know

        `bookingId` (e.g. you're processing bookings fetched from

        `GET /bookings`). If your check-in point only has the candidate's

        `attendanceCode` — the normal case for a desk or QR scan — use

        `POST /attendance-codes/{attendanceCode}/check-in` instead, which
        resolves

        the booking from the code itself. Both emit

        `booking.attendance_updated` to your webhook endpoint. The booking

        does not need to already be past its `scheduledStartAt` — you can

        check a candidate in early.
      operationId: updateBookingAttendance
      parameters:
        - name: bookingId
          in: path
          required: true
          schema:
            type: integer
          example: 9001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateBookingAttendanceRequest'
            examples:
              attended:
                value:
                  status: ATTENDED
                  occurredAt: '2026-09-10T02:05:00.000Z'
                  method: QR_SCAN
      responses:
        '200':
          description: Attendance recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateBookingAttendanceResponse'
              examples:
                attended:
                  value:
                    status: success
                    data:
                      id: 9001
                      bookingScheduleId: 501
                      bookingLinkId: 8001
                      entityType: JOB_CANDIDATE
                      entityId: '55021'
                      firstName: Jane
                      lastName: Doe
                      email: jane.doe@example.com
                      phone: '+15551234567'
                      scheduledStartAt: '2026-09-12T02:00:00.000Z'
                      scheduledEndAt: '2026-09-12T02:30:00.000Z'
                      timezone: Asia/Manila
                      status: ATTENDED
                      selectedFormat: null
                      selectedLocation: null
                      bookingAnswers: null
                      meetingLink: null
                      attendanceCode: null
                      attendanceCodeExpiresAt: null
                      attendanceMarkedVia: PARTNER_API
                      attendanceMarkedAt: '2026-09-12T02:05:00.000Z'
                      createdAt: '2026-09-10T02:00:00.000Z'
                      updatedAt: '2026-09-12T02:05:00.000Z'
        '400':
          description: Invalid `status`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                invalidStatus:
                  value:
                    error:
                      code: INVALID_REQUEST
                      type: validation_error
                      message: status must be ATTENDED or NOT_ATTENDED.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: No booking with this id in your company.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                notFound:
                  value:
                    error:
                      code: NOT_FOUND
                      type: not_found
                      message: Booking not found
        '409':
          description: Booking is `CANCELLED` and cannot have attendance recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                cancelled:
                  value:
                    error:
                      code: BOOKING_CANCELLED
                      type: validation_error
                      message: A cancelled booking cannot have attendance recorded.
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    UpdateBookingAttendanceRequest:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          description: The attendance outcome to record.
          enum:
            - ATTENDED
            - NOT_ATTENDED
        occurredAt:
          type: string
          format: date-time
          description: >-
            When the check-in or no-show actually happened. Defaults to the time
            this request is received if omitted.
        method:
          type: string
          description: >-
            How you captured this attendance event on your side (e.g. your own
            QR scan, a front-desk check-in). Free text, stored alongside the
            fixed `PARTNER_API` value recorded in `Booking.attendanceMarkedVia`.
          examples:
            - QR_SCAN
        note:
          type:
            - string
            - 'null'
    UpdateBookingAttendanceResponse:
      type: object
      required:
        - status
        - data
      properties:
        status:
          type: string
          const: success
        data:
          $ref: '#/components/schemas/Booking'
    ApiError:
      type: object
      description: Canonical error envelope used by most non-authentication errors.
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/ApiErrorBody'
    Booking:
      type: object
      description: >-
        A single scheduled appointment, created when a candidate books a slot on
        a booking link.
      required:
        - id
        - bookingScheduleId
        - bookingLinkId
        - entityType
        - entityId
        - scheduledStartAt
        - scheduledEndAt
        - timezone
        - status
      properties:
        id:
          type: integer
          examples:
            - 9001
        bookingScheduleId:
          type: integer
        bookingLinkId:
          type: integer
          description: >-
            The link this booking was made on. Always present — the reliable
            field to filter or correlate by via `GET /bookings?bookingLinkId=`,
            regardless of `entityType`.
        entityType:
          type: string
          description: |
            How this candidate was identified. Not a fixed enum — known
            values today are `JOB_CANDIDATE` (`entityId` matches a
            `jobCandidateId` from the
            [Jobs](/api-reference/jobs)/[Candidates](/api-reference/candidates)
            APIs), `OUTREACH_CAMPAIGN_CANDIDATE` (sourced from an outreach
            campaign flow, company-scoped or private), and `NOVA_CANDIDATE`
            (a candidate created through TapTalent's Agentic Onboarding
            flow, with no job or campaign attached). Only `JOB_CANDIDATE`
            has a matching lookup elsewhere in this API, via the
            Jobs/Candidates endpoints — treat `OUTREACH_CAMPAIGN_CANDIDATE`
            and `NOVA_CANDIDATE` ids as opaque. Always present.
          examples:
            - JOB_CANDIDATE
        entityId:
          type: string
          description: |
            The id of the underlying record within `entityType`'s source —
            not necessarily a "candidate" record (e.g. a lead, for
            `OUTREACH_CAMPAIGN_CANDIDATE`). Always a string — some sources
            use ids too large to round-trip safely as a JSON number.
          examples:
            - '55021'
        firstName:
          type:
            - string
            - 'null'
          description: >-
            Snapshotted from the resolved entity's own record when the link was
            created, not supplied by the caller.
        lastName:
          type:
            - string
            - 'null'
        email:
          type:
            - string
            - 'null'
          format: email
        phone:
          type:
            - string
            - 'null'
        scheduledStartAt:
          type: string
          format: date-time
          description: Appointment start time, in UTC.
        scheduledEndAt:
          type: string
          format: date-time
        timezone:
          type: string
          description: The schedule's timezone at booking time, for display purposes.
        status:
          $ref: '#/components/schemas/BookingStatus'
        selectedFormat:
          oneOf:
            - $ref: '#/components/schemas/BookingFormat'
            - type: 'null'
          description: Set only for bookings made against a `BOTH`-mode schedule.
        selectedLocation:
          oneOf:
            - $ref: '#/components/schemas/BookingLocation'
            - type: 'null'
          description: |
            For `EVENT`-profile schedules only: the location the candidate
            picked, from `GET /booking-schedules/{bookingScheduleId}/locations`.
            `null` for `INTERVIEW`-profile bookings.
        bookingAnswers:
          type:
            - object
            - 'null'
          description: |
            For `EVENT`-profile schedules only: the candidate's answers,
            keyed by the `id` of each question from
            `GET /booking-schedules/{bookingScheduleId}/questions`. Each
            value's shape follows that question's `type` — a string for
            `text`/`textarea`/`phone`/`single_choice`, an array of strings
            for `multi_choice`. `null` for `INTERVIEW`-profile bookings.
          additionalProperties: true
        meetingLink:
          type:
            - string
            - 'null'
          format: uri
          description: Video meeting link, for online appointments.
        attendanceCode:
          type:
            - string
            - 'null'
          description: |
            Short check-in code issued for every booking, regardless of the
            schedule's profile — consumable at a desk (typed in, or scanned
            as a QR) via `POST /attendance-codes/{attendanceCode}/check-in` to
            mark attendance without needing to already know `bookingId`.
            `null` once consumed or invalidated.
        attendanceCodeExpiresAt:
          type:
            - string
            - 'null'
          format: date-time
        attendanceMarkedVia:
          oneOf:
            - $ref: '#/components/schemas/AttendanceMarkedVia'
            - type: 'null'
        attendanceMarkedAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ApiErrorBody:
      type: object
      description: Canonical error object carried under the `error` key.
      required:
        - code
        - type
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code, e.g. `INVALID_REQUEST`.
          examples:
            - INVALID_REQUEST
        type:
          type: string
          description: Error category.
          enum:
            - validation_error
            - internal_error
            - not_found
            - authorization_error
            - resource_error
            - payment_error
            - subscription_error
        message:
          type: string
          description: Human-readable error message.
        details:
          type: object
          description: Optional per-field validation messages or structured error context.
          additionalProperties: true
    AuthMessageError:
      type: object
      description: >-
        Flat authentication error shape (does not use the canonical `error`
        envelope).
      required:
        - message
      properties:
        message:
          type: string
          examples:
            - Invalid API key
    AuthCodeMessageError:
      type: object
      description: >-
        Flat authentication error shape returned when the account subscription
        is inactive.
      required:
        - code
        - message
      properties:
        code:
          type: string
          examples:
            - ACCOUNT_INACTIVE
        message:
          type: string
          examples:
            - >-
              Your subscription is inactive. Please renew your plan to continue
              using this feature.
    AuthApiKeyError:
      type: object
      description: >-
        Flat authentication error shape returned when the API key does not
        exist.
      required:
        - message
        - isApiKeyExists
      properties:
        message:
          type: string
          examples:
            - API key not found
        isApiKeyExists:
          type: boolean
    BookingStatus:
      type: string
      description: |
        Lifecycle status of a booking. `ACTIVE` is the only status a booking
        can be rescheduled or cancelled from. Rescheduling cancels the
        current booking (its status becomes `CANCELLED`) and creates a new
        `ACTIVE` booking — see `RescheduleBookingResponse`.
      enum:
        - ACTIVE
        - ATTENDED
        - NOT_ATTENDED
        - CANCELLED
      examples:
        - ACTIVE
    BookingFormat:
      type: string
      description: >-
        The attendance format the candidate selected, for `BOTH`-mode schedules
        only.
      enum:
        - ONLINE
        - ONSITE
      examples:
        - ONSITE
    BookingLocation:
      type: object
      x-inferred: true
      description: >-
        A location a candidate can pick when booking an `EVENT`-profile
        schedule.
      required:
        - id
        - type
        - label
      properties:
        id:
          type: integer
          examples:
            - 701
        type:
          type: string
          description: >-
            How this location is attended. `video`/`phone` are virtual;
            `in_person` and `custom` are physical or bespoke.
          enum:
            - video
            - phone
            - in_person
            - custom
          examples:
            - in_person
        label:
          type: string
          description: Short display name, shown to the candidate in the location picker.
          examples:
            - Downtown Office — 3rd Floor
        details:
          type:
            - string
            - 'null'
          description: >-
            Free text appropriate to `type` — a street address for `in_person`,
            a meeting link for `video`, a phone number for `phone`, or arbitrary
            text for `custom`.
          examples:
            - 123 Main St, Manila
        instructions:
          type:
            - string
            - 'null'
          description: >-
            Extra guidance shown alongside `details` (e.g. "Ring the bell", "Ask
            for the 3rd floor front desk").
        lat:
          type:
            - number
            - 'null'
          description: >-
            Latitude, for `in_person` locations with a map pin set. `null` if
            none was set.
          examples:
            - 14.5547
        lng:
          type:
            - number
            - 'null'
          description: Longitude, paired with `lat`.
          examples:
            - 121.0244
        photoUrls:
          type: array
          description: >-
            Up to 5 photo URLs configured for this location, in display order
            (the first is the cover photo). Empty array if none were uploaded.
          items:
            type: string
            format: uri
          examples:
            - - https://cdn.taptalent.io/locations/701/lobby.jpg
    AttendanceMarkedVia:
      type: string
      description: |
        How attendance was captured. `QR_DESK` and `CODE_DESK` are walk-up
        desk flows (the candidate's QR or attendance code scanned or typed
        in); `ADMIN_UI` is a recruiter marking attendance manually in the
        TapTalent dashboard; `SELF_LINK` is the candidate self-marking from
        their own confirmation page; `PARTNER_API` is this API's
        `POST /bookings/{bookingId}/attendance`.
      enum:
        - QR_DESK
        - CODE_DESK
        - ADMIN_UI
        - SELF_LINK
        - PARTNER_API
      examples:
        - QR_DESK
  responses:
    Unauthorized:
      description: |
        Authentication failed. Note that authentication errors use flat body
        shapes rather than the canonical `error` envelope.
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/AuthMessageError'
              - $ref: '#/components/schemas/AuthCodeMessageError'
              - $ref: '#/components/schemas/AuthApiKeyError'
          examples:
            invalidApiKey:
              summary: Invalid API key
              value:
                message: Invalid API key
            accountInactive:
              summary: Subscription inactive
              value:
                code: ACCOUNT_INACTIVE
                message: >-
                  Your subscription is inactive. Please renew your plan to
                  continue using this feature.
            apiKeyNotFound:
              summary: API key not found
              value:
                message: API key not found
                isApiKeyExists: false
    TooManyRequests:
      x-inferred: true
      description: |
        Rate limit exceeded. Rate limits are applied at the company level; the
        response body below is inferred because the current documentation
        mentions handling 429 responses but does not publish a body. Retry
        with exponential backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            rateLimited:
              summary: Rate limit exceeded (inferred example)
              value:
                error:
                  code: RATE_LIMIT_EXCEEDED
                  type: validation_error
                  message: Too many requests. Please retry with exponential backoff.
    InternalError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            internalError:
              summary: Internal error
              value:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: Something went wrong.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: |
        Company-scoped API key. Production keys are prefixed `sk_live_`,
        sandbox keys `sk_test_`, each followed by 22 base62 characters
        (pattern `^sk_(live|test)_[0-9A-Za-z]{22}$`). Generate keys in the
        TapTalent dashboard under Account Settings → Developers → API Key
        Management; a key is shown once at generation and old keys are
        invalidated immediately on regeneration.

````