Wellhub Jobs API

Endpoints for managing eligibility batch jobs. A job follows a lifecycle: Create → Add Items → Submit → Monitor. After submission, the job transitions through the following statuses: - `PENDING` — job has been submitted and is queued. - `VALIDATING` — intermediate state while items are being validated. - `SUCCEEDED` — all items processed successfully (terminal). - `SUCCEEDED_WITH_ERRORS` — job has been partially processed, with error entries that must be fixed (terminal). → **Call `GET /errors` to review failures.** - `REJECTED` — job was rejected due to validation issues (terminal). → **Call `GET /errors` to review failures.** - `INTERNAL_SERVER_ERROR` — a server-side error occurred during processing; it is recommended to try again (terminal). → **Retry job submission.**

Documentation

Specifications

Other Resources

OpenAPI Specification

wellhub-jobs-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Integrations Companies Jobs API
  description: 'Integrations exposes a public API for Wellhub clients.


    ### API Credentials Tutorial


    To interact with the API, you will need to obtain a Bearer Access Token. Follow these steps:


    1. **Obtain your credentials**: Log in to your account and locate your `client_id` and `client_secret`.

    2. **Request a token**: Call `POST /oauth/token` using the `client_credentials` grant type, passing your `client_id` and `client_secret` as form data.

    3. **Use the token**: Include it in every subsequent request as follows:


    ```

    ''Authorization'': ''Bearer YOUR_ACCESS_TOKEN_HERE''

    ```


    Tokens are short-lived. Make sure to request a new one when the current one expires.'
  version: v1.0.0
servers:
- url: https://api.clients.wellhub.com
tags:
- name: Jobs
  description: 'Endpoints for managing eligibility batch jobs. A job follows a lifecycle: Create → Add Items → Submit → Monitor.


    After submission, the job transitions through the following statuses:

    - `PENDING` — job has been submitted and is queued.

    - `VALIDATING` — intermediate state while items are being validated.

    - `SUCCEEDED` — all items processed successfully (terminal).

    - `SUCCEEDED_WITH_ERRORS` — job has been partially processed, with error entries that must be fixed (terminal). → **Call `GET /errors` to review failures.**

    - `REJECTED` — job was rejected due to validation issues (terminal). → **Call `GET /errors` to review failures.**

    - `INTERNAL_SERVER_ERROR` — a server-side error occurred during processing; it is recommended to try again (terminal). → **Retry job submission.**'
paths:
  /v1/eligibility/jobs:
    post:
      tags:
      - Jobs
      summary: Create a new eligibility job
      description: Creates a new eligibility batch job in draft state. After creation, add items to the job using `POST /v1/eligibility/jobs/{job-id}/items`, then submit it using `POST /v1/eligibility/jobs/{job-id}/submit`.
      responses:
        '201':
          description: Created. Returns the newly created job's ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobResponse'
              example:
                id: d46fb00b-79b1-4a89-9bd6-523889d0417f
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden. The authenticated entity does not have permission to create jobs.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
  /v1/eligibility/jobs/{job-id}/items:
    get:
      tags:
      - Jobs
      summary: List job items
      description: Returns a paginated list of all items that have been added to the specified job.
      parameters:
      - name: job-id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        example: d46fb00b-79b1-4a89-9bd6-523889d0417f
        description: The UUID of the job.
      - name: cursor
        in: query
        required: false
        schema:
          type: string
        description: Pagination cursor returned from the previous response. Omit to retrieve the first page.
      responses:
        '200':
          description: OK. Returns a paginated list of job items.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobItemsResponse'
        '400':
          description: Bad Request. Invalid `job-id` format.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '404':
          description: Not Found. No job found with the given ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
    post:
      tags:
      - Jobs
      summary: Add items to a job
      description: Adds a batch of employee records to an existing draft job. Each item represents a single employee operation (CREATE, UPDATE, or DELETE). A request must contain between 1 and 500 items. The `company_tax_id` and `operation` fields are required per item.
      parameters:
      - name: job-id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        example: d46fb00b-79b1-4a89-9bd6-523889d0417f
        description: The UUID of the draft job to add items to.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              minItems: 1
              maxItems: 500
              items:
                $ref: '#/components/schemas/CreateJobItem'
            example:
            - operation: CREATE
              company_tax_id: 12.345.678/0001-99
              email: jane.doe@example.com
              full_name: Jane Doe
              employee_id: EMP001
              national_id: 123.456.789-00
              department: Engineering
              cost_center: CC-001
              office_zip_code: 01310-100
              eligible_to_payroll: true
      responses:
        '204':
          description: No Content. All items were successfully added to the job.
        '400':
          description: 'Bad Request. Possible causes:

            1. Invalid `job-id` format.

            2. Request body is empty or contains more than 500 items.

            3. One or more items failed validation (missing `operation` or `company_tax_id`, invalid `operation` value).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MultipleErrorResponse'
              example:
                message: validation error
                reason: invalid request body
                errors:
                - field: '[0].operation'
                  message: must be one of CREATE, UPDATE, DELETE
                - field: '[1].company_tax_id'
                  message: cannot be blank
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '404':
          description: Not Found. No job found with the given ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '413':
          description: Request Entity Too Large. The request payload exceeds the allowed size limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
  /v1/eligibility/jobs/{job-id}/submit:
    post:
      tags:
      - Jobs
      summary: Submit a job for processing
      description: Submits a draft job for asynchronous processing. The job must have at least one item added before it can be submitted. Once submitted, the job transitions out of draft state and cannot be modified. Use `GET /v1/eligibility/jobs/{job-id}/status` to monitor progress.
      parameters:
      - name: job-id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        example: d46fb00b-79b1-4a89-9bd6-523889d0417f
        description: The UUID of the job to submit.
      responses:
        '202':
          description: Accepted. The job has been submitted and is queued for processing. **Response body is empty — do not attempt to parse it.**
        '400':
          description: Bad Request. Invalid `job-id` format or job has no items.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '404':
          description: Not Found. No job found with the given ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '409':
          description: Conflict. The job has already been submitted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '422':
          description: Unprocessable Entity. The job cannot be submitted in its current state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
  /v1/eligibility/jobs/{job-id}/status:
    get:
      tags:
      - Jobs
      summary: Get job status
      description: Returns the current status of a submitted job, including processing statistics (number of newcomers, leavers, and updaters processed).
      parameters:
      - name: job-id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        example: d46fb00b-79b1-4a89-9bd6-523889d0417f
        description: The UUID of the job.
      responses:
        '200':
          description: OK. Returns the job status and statistics.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobStatusResponse'
              example:
                id: d46fb00b-79b1-4a89-9bd6-523889d0417f
                status: SUCCEEDED
                updated_at: '2025-04-01T19:30:54Z'
                statistics:
                  newcomers: 10
                  leavers: 2
                  updaters: 5
        '400':
          description: Bad Request. Invalid `job-id` format.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '404':
          description: Not Found. No job found with the given ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
  /v1/eligibility/jobs/{job-id}/errors:
    get:
      tags:
      - Jobs
      summary: List job errors
      description: 'Returns a paginated list of processing errors for the specified job. Use this after a job has been submitted to identify records that failed processing.


        > **ℹ️ When to call this.** Errors are populated for jobs in `SUCCEEDED_WITH_ERRORS` or `REJECTED` terminal status. Calling this endpoint for jobs in other statuses will return an empty list.'
      parameters:
      - name: job-id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        example: d46fb00b-79b1-4a89-9bd6-523889d0417f
        description: The UUID of the job.
      - name: cursor
        in: query
        required: false
        schema:
          type: string
        description: Pagination cursor returned from the previous response. Omit to retrieve the first page.
      responses:
        '200':
          description: OK. Returns a paginated list of job errors.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobErrorsResponse'
              example:
                data:
                - change_number: 1
                  company_tax_id: 12.345.678/0001-99
                  error_type: INVALID_FIELD
                  field_name: email
                  field_value: not-an-email
                  recovered_by: null
                cursor: null
        '400':
          description: Bad Request. Invalid `job-id` format.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '401':
          description: Unauthorized. Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
        '500':
          description: Internal Server Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
      security:
      - OAuth2: []
components:
  schemas:
    Statistics:
      type: object
      properties:
        newcomers:
          type: integer
          description: Number of employees successfully created.
          example: 10
        leavers:
          type: integer
          description: Number of employees successfully deleted.
          example: 2
        updaters:
          type: integer
          description: Number of employees successfully updated.
          example: 5
    MultipleErrorResponse:
      type: object
      properties:
        message:
          type: string
          description: High-level error summary.
          example: validation error
        reason:
          type: string
          description: Machine-readable error reason code.
          example: invalid request body
        errors:
          type: array
          items:
            $ref: '#/components/schemas/FieldError'
          description: List of individual field-level validation errors.
    CreateJobItem:
      type: object
      required:
      - operation
      - company_tax_id
      properties:
        operation:
          type: string
          enum:
          - CREATE
          - UPDATE
          - DELETE
          description: The operation to perform for this employee record.
        company_tax_id:
          type: string
          description: The tax ID of the company this employee belongs to.
          example: 12.345.678/0001-99
        email:
          type: string
          description: Employee's email address.
          example: jane.doe@example.com
        full_name:
          type: string
          description: Employee's full name.
          example: Jane Doe
        employee_id:
          type: string
          description: Client-defined employee identifier.
          example: EMP001
        national_id:
          type: string
          description: Employee's national identifier.
          example: 123.456.789-00
        payroll_id:
          type: string
          description: Payroll identifier for the employee.
          example: PAY-9876
        department:
          type: string
          description: Department the employee belongs to.
          example: Engineering
        office_zip_code:
          type: string
          description: ZIP code of the employee's office location.
          example: 01310-100
        cost_center:
          type: string
          description: Cost center associated with the employee.
          example: CC-001
        mobile_number:
          type: string
          description: Employee's mobile phone number.
          example: '+5511999999999'
        discount_subset_id:
          type: string
          description: Identifier for the discount subset applicable to this employee.
          example: SUBSET-A
        eligible_to_payroll:
          type: boolean
          description: Whether the employee is eligible for payroll deduction.
          example: true
        custom_fields:
          type: object
          additionalProperties: true
          description: Optional map of additional custom attributes for the employee. Values are not validated by the platform.
    JobItemsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/JobItemResponse'
        cursor:
          type: string
          nullable: true
          description: Cursor for the next page. `null` if no more results.
    JobErrorsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/JobError'
        cursor:
          type: string
          nullable: true
          description: Cursor for the next page. `null` if no more results.
    HTTPError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message.
        trace_id:
          type: string
          description: Unique trace identifier for debugging and support.
    JobError:
      type: object
      properties:
        change_number:
          type: integer
          nullable: true
          description: The sequence number of the job item that caused the error.
        company_tax_id:
          type: string
          nullable: true
          description: Tax ID of the company associated with the failed item. Useful for tracing which company an error belongs to when a job spans multiple companies.
          example: 12.345.678/0001-99
        error_type:
          type: string
          description: Type/code of the error that occurred.
        field_name:
          type: string
          nullable: true
          description: Name of the field that caused the error, if applicable.
        field_value:
          type: string
          nullable: true
          description: Value of the field that caused the error, if applicable.
        recovered_by:
          type: string
          nullable: true
          description: Identifier of the process or user that recovered this error, if applicable.
    JobItemResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Internal identifier for this job item.
        job_id:
          type: string
          format: uuid
          description: The UUID of the parent job.
        operation:
          type: string
          enum:
          - CREATE
          - UPDATE
          - DELETE
          description: The operation applied for this item.
        company_tax_id:
          type: string
          description: Tax ID of the associated company.
        email:
          type: string
          nullable: true
        full_name:
          type: string
          nullable: true
        employee_id:
          type: string
          nullable: true
        national_id:
          type: string
          nullable: true
        payroll_id:
          type: string
          nullable: true
        department:
          type: string
          nullable: true
        office_zip_code:
          type: string
          nullable: true
        cost_center:
          type: string
          nullable: true
        mobile_number:
          type: string
          nullable: true
        discount_subset_id:
          type: string
          nullable: true
        eligible_to_payroll:
          type: boolean
          nullable: true
        custom_fields:
          type: object
          additionalProperties: true
          nullable: true
        change_number:
          type: integer
          description: Sequential number assigned to this item within the job.
        created_at:
          type: string
          format: date-time
          description: Timestamp when this item was added to the job.
    FieldError:
      type: object
      properties:
        field:
          type: string
          description: JSON path of the field that failed validation.
          example: '[0].operation'
        message:
          type: string
          description: Human-readable description of the validation failure.
          example: must be one of CREATE, UPDATE, DELETE
    JobStatusResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The UUID of the job.
        status:
          type: string
          enum:
          - PENDING
          - VALIDATING
          - SUCCEEDED
          - SUCCEEDED_WITH_ERRORS
          - REJECTED
          - INTERNAL_SERVER_ERROR
          description: 'Current processing status of the job. Lifecycle: `PENDING` → `VALIDATING` → `SUCCEEDED` / `SUCCEEDED_WITH_ERRORS` / `REJECTED` / `INTERNAL_SERVER_ERROR`.'
          example: SUCCEEDED
        updated_at:
          type: string
          format: date-time
          description: Timestamp of the last status update.
        statistics:
          $ref: '#/components/schemas/Statistics'
    JobResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The UUID of the newly created job.
          example: d46fb00b-79b1-4a89-9bd6-523889d0417f
  securitySchemes:
    OAuth2:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Bearer token obtained from `POST /oauth/token` using the client_credentials grant type.