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

# Pull and confirm events

> One call does both jobs. Send the `ack` ids of the events you already processed, and get the next events back. An event keeps coming back until you put its id in `ack`. Use it when you cannot expose a URL, and as a safety net next to the webhook.

**Scope:** `events:read`



## OpenAPI

````yaml /blue-collar-api/api-reference/openapi.json post /events/pull
openapi: 3.1.0
info:
  title: Record Blue Collar API
  version: 1.0.0
  description: >-
    Run Record candidate verification from your own system. You need two things:
    your **key id** and your **secret**. Everything else is generated. See
    Authentication for how.
servers:
  - url: https://api-bc.userecord.io/api/v1/partner
    description: Blue Collar API
security: []
tags:
  - name: Skills
    description: The skill taxonomy, read live a page at a time
  - name: Skill requests
    description: Ask Record to add a missing skill
  - name: Lookups
    description: >-
      Lookups for filling in a job mandate: places in India, the countries an
      abroad job can be in, and the employment types and shifts the playground
      offers
  - name: Workflows
    description: >-
      Your organisation's blue-collar workflows (read all; change and
      soft-delete only the ones you created)
  - name: Job mandates
    description: >-
      Your organisation's job mandates, addressed by Record's mandate_id (read
      all; change only the ones you created)
  - name: Campaigns
    description: Contact candidates for one of your jobs and verify them. Spends credits
  - name: Results
    description: >-
      What Record collected from each candidate: status (pending, completed,
      declined, failed) and an output of answers and verdicts
  - name: Events
    description: >-
      Pull your result events and acknowledge them: the safety net behind the
      webhook, and a way to receive results without exposing a URL
  - name: Webhooks
    description: >-
      Endpoints that Record POSTs result events to: signed, retried until you
      acknowledge, replayable
  - name: Analytics
    description: >-
      The workflow Overview analytics of the Record playground: funnel,
      channels, follow-ups, calls, drop-offs, languages (read-only, scope
      analytics:read)
paths:
  /events/pull:
    post:
      tags:
        - Events
      summary: Pull and confirm events
      description: >-
        One call does both jobs. Send the `ack` ids of the events you already
        processed, and get the next events back. An event keeps coming back
        until you put its id in `ack`. Use it when you cannot expose a URL, and
        as a safety net next to the webhook.


        **Scope:** `events:read`
      operationId: pullEvents
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ack:
                  type: array
                  items:
                    type: string
                    pattern: ^evt_[a-f0-9]{32}$
                  maxItems: 100
                  default: []
                  description: >-
                    Up to 100 ids of events you processed. They are acknowledged
                    before the page is read, so they do not come back
                status:
                  type: string
                  enum:
                    - unacked
                    - all
                  default: unacked
                  description: >-
                    `unacked` (default) gives only events you have not
                    confirmed. `all` replays history (use it with `from`).
                type:
                  type: string
                  enum:
                    - candidate.result
                  description: Only this event type.
                from:
                  type: string
                  format: date-time
                  description: Only events created at or after this time (replay)
                after:
                  type: integer
                  minimum: 0
                  description: Only events with a higher `sequence` than this
                limit:
                  type: integer
                  minimum: 1
                  maximum: 100
                  default: 100
                  description: 1 to 100, default 100
              additionalProperties: false
            example:
              ack:
                - evt_9c2e4a6b8d0f1234567890abcdef1234
              status: unacked
              limit: 100
      responses:
        '200':
          description: One page, oldest first
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    const: true
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            event_id:
                              type: string
                              description: >-
                                Stable forever. Keep the ones you processed and
                                skip repeats
                            type:
                              type: string
                              enum:
                                - candidate.result
                            api_version:
                              type: string
                            created_at:
                              type: string
                              description: When the change happened
                            mode:
                              type: string
                              enum:
                                - live
                                - test
                            version:
                              type: integer
                              description: >-
                                Rises each time the same candidate's result
                                changes. Keep the highest
                            sequence:
                              type: integer
                              description: Order of events in your stream
                            backfill:
                              type: boolean
                              description: >-
                                true when the event was created for a webhook
                                backfill
                            acknowledged:
                              type: boolean
                              description: >-
                                true once you acknowledged it (webhook 2xx, or
                                listed in `ack` of POST /events/pull)
                            data:
                              type: object
                              properties:
                                candidate_id:
                                  type: string
                                external_id:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                  description: >-
                                    Your own id for the candidate, if you sent
                                    one
                                campaign_id:
                                  type: string
                                mandate_id:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                job_id:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                  description: >-
                                    Your job id; null for a mandate created
                                    without one
                                workflow_id:
                                  type: string
                                name:
                                  type: string
                                status:
                                  type: string
                                  enum:
                                    - pending
                                    - completed
                                    - declined
                                    - failed
                                  description: >-
                                    pending: not finished yet. completed:
                                    finished, `output` holds what Record
                                    collected. declined: the candidate said not
                                    interested. failed: no result could be got,
                                    see `reason`
                                reason:
                                  anyOf:
                                    - type: string
                                      enum:
                                        - undeliverable
                                        - no_response
                                    - type: 'null'
                                  description: >-
                                    Only for failed. undeliverable: the invite
                                    could not be delivered. no_response: every
                                    attempt went unanswered
                                attempts:
                                  type: integer
                                  description: >-
                                    Times Record tried to reach the candidate:
                                    invite, follow-ups and phone calls
                                language:
                                  type: string
                                location_name:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                  description: >-
                                    The town the candidate was in when they
                                    allowed location on the verification link.
                                    null when they denied it, it could not be
                                    looked up, or they verified by phone call
                                metadata:
                                  type: object
                                  additionalProperties:
                                    anyOf:
                                      - type: string
                                      - type: number
                                      - type: boolean
                                  description: >-
                                    The `metadata` you sent for this candidate,
                                    unchanged
                                started_at:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                  description: When the invite went out
                                completed_at:
                                  anyOf:
                                    - type: string
                                    - type: 'null'
                                updated_at:
                                  type: string
                                output:
                                  type: object
                                  properties:
                                    enrichment:
                                      type: object
                                      properties:
                                        qualified:
                                          anyOf:
                                            - type: boolean
                                            - type: 'null'
                                        answers:
                                          type: object
                                          additionalProperties:
                                            anyOf:
                                              - type: string
                                              - type: 'null'
                                        answers_native:
                                          type: object
                                          additionalProperties:
                                            type: string
                                      description: >-
                                        Answers to your screening questions,
                                        keyed by the question's text
                                    skill_verification:
                                      type: object
                                      properties:
                                        verdict:
                                          anyOf:
                                            - type: string
                                            - type: 'null'
                                        total_score:
                                          anyOf:
                                            - type: number
                                            - type: 'null'
                                        is_partial:
                                          type: boolean
                                        answered:
                                          anyOf:
                                            - type: number
                                            - type: 'null'
                                        total:
                                          anyOf:
                                            - type: number
                                            - type: 'null'
                                        skills:
                                          type: array
                                          items:
                                            type: object
                                            properties:
                                              name:
                                                type: string
                                              rating:
                                                type: string
                                        call_recording_url:
                                          anyOf:
                                            - type: string
                                            - type: 'null'
                                          description: >-
                                            The phone call's recording, when they
                                            verified by call
                                        answers:
                                          type: array
                                          items:
                                            type: object
                                            properties:
                                              skill:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              question:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              answer:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              answer_native:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              rating:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              summary:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              video_url:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                                description: The video of this answer
                                      description: >-
                                        The skill-verification result and what
                                        the candidate said
                                    interest_collection:
                                      type: object
                                      properties:
                                        current_role:
                                          anyOf:
                                            - type: string
                                            - type: 'null'
                                        other_roles:
                                          type: array
                                          items:
                                            type: object
                                            properties:
                                              role:
                                                type: string
                                              years:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                        answers:
                                          type: array
                                          items:
                                            type: object
                                            properties:
                                              role:
                                                type: string
                                              summary:
                                                anyOf:
                                                  - type: string
                                                  - type: 'null'
                                              transcripts:
                                                type: array
                                                items:
                                                  type: object
                                                  properties:
                                                    label:
                                                      type: string
                                                    text:
                                                      type: string
                                      description: Other roles the candidate is open to
                                  description: >-
                                    What Record collected. A section appears
                                    only once its data exists, and only if that
                                    check ran for the job
                      count:
                        type: integer
                      acknowledged:
                        type: integer
                        description: >-
                          How many of the `ack` ids were newly acknowledged by
                          this call
                      pending:
                        anyOf:
                          - type: integer
                          - type: 'null'
                        description: How many unacknowledged events you have in all
                      next_cursor:
                        anyOf:
                          - type: string
                          - type: 'null'
                        description: Pass as `after` for the next page
                      has_more:
                        type: boolean
              example:
                success: true
                data:
                  items:
                    - event_id: evt_9c2e4a6b8d0f1234567890abcdef1234
                      type: candidate.result
                      api_version: '2026-10-01'
                      created_at: '2026-10-05T12:41:11.000Z'
                      mode: test
                      version: 1
                      sequence: 482913
                      acknowledged: false
                      data:
                        candidate_id: a3f1c9d2-7b44-4e0a-9c1d-5e6f7a8b9c01
                        external_id: cand-88231
                        campaign_id: asmnt_9f2c41d7a8b3e65f
                        mandate_id: JM_261009101612456H3N8W2L5C9V1Z4
                        job_id: job-10452
                        workflow_id: WF_BG_261009101530123K7M2P9Q4X7R5T8
                        name: Ravi Kumar
                        status: completed
                        reason: null
                        attempts: 3
                        language: tamil
                        location_name: Coimbatore
                        metadata:
                          ats_application_id: app_991
                        started_at: '2026-10-05T09:30:00.000Z'
                        completed_at: '2026-10-05T12:41:10.000Z'
                        updated_at: '2026-10-05T12:41:10.000Z'
                        output:
                          enrichment:
                            qualified: true
                            answers:
                              Do you have a valid driving licence?: 'yes'
                              Why do you want this job?: I want a stable job near home
                          skill_verification:
                            verdict: Good Fit
                            total_score: 78
                            is_partial: false
                            answered: 3
                            total: 3
                            skills:
                              - name: Forklift Basic Operation
                                rating: Strong
                            call_recording_url: null
                            answers:
                              - skill: Forklift Basic Operation
                                question: What do you check before lifting a load?
                                answer: >-
                                  I check the load weight against the forklift
                                  rating and that the forks are level.
                                answer_native: null
                                rating: Strong
                                summary: Mentions weight limit and fork position.
                                video_url: >-
                                  https://storage.googleapis.com/record-interviews/sess_91c2/q1.mp4
                          interest_collection:
                            current_role: Forklift Operator
                            other_roles:
                              - role: Store Keeper
                                years: 1 to 2 years
                  count: 1
                  acknowledged: 1
                  pending: 1
                  next_cursor: null
                  has_more: false
        '400':
          description: >-
            `VALIDATION_FAILED`: An `ack` id that is not an event id, more than
            100 ids, a bad date, or `limit` above 100.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - ApiKey: []
          SecretKey: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            pcall POST "/api/v1/partner/events/pull" '{
              "ack": [
                "evt_9c2e4a6b8d0f1234567890abcdef1234"
              ],
              "status": "unacked",
              "limit": 100
            }'
        - lang: javascript
          label: JavaScript
          source: |-
            const res = await call("POST", "/api/v1/partner/events/pull", {
              "ack": [
                "evt_9c2e4a6b8d0f1234567890abcdef1234"
              ],
              "status": "unacked",
              "limit": 100
            });
            const { data } = await res.json();
        - lang: python
          label: Python
          source: |-
            res = call("POST", "/api/v1/partner/events/pull", {
                "ack": [
                    "evt_9c2e4a6b8d0f1234567890abcdef1234"
                ],
                "status": "unacked",
                "limit": 100
            })
            data = res.json()["data"]
components:
  schemas:
    Error:
      type: object
      properties:
        success:
          const: false
          type: boolean
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - VALIDATION_FAILED
                - LIMIT_EXCEEDED
                - UNAUTHORIZED
                - SCOPE_MISSING
                - FORBIDDEN
                - HTTPS_REQUIRED
                - NOT_FOUND
                - CONFLICT
                - WORKFLOW_IN_USE
                - INSUFFICIENT_CREDITS
                - IDEMPOTENCY_KEY_REQUIRED
                - IDEMPOTENCY_KEY_REUSED
                - IDEMPOTENCY_IN_PROGRESS
                - PAYLOAD_TOO_LARGE
                - UNSUPPORTED_MEDIA_TYPE
                - RATE_LIMITED
                - COOLDOWN
                - DAILY_CAP
                - SERVICE_DISABLED
                - SERVER_ERROR
            message:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  path:
                    type: string
                  message:
                    type: string
            request_id:
              type: string
              description: Quote it to Record support
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: Your key id, `VFN_TEST_…` or `VFN_LIVE_…`. Sent on every request.
    SecretKey:
      type: apiKey
      in: header
      name: x-secret-key
      description: >-
        Your secret, `VFN_SK_…`. **Not a real header, and never sent to the
        API.** It is only a form field for Try it, which uses it to sign your
        request in your browser. In your own code you sign each request with the
        secret and send `x-api-key`, `x-timestamp` and `x-signature` (see
        Authentication).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.