> ## 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.

# Create or update a pipeline stage

> Creates a new stage or updates an existing stage in a pipeline,
depending on the request body: when `stageId` is present the existing
stage is updated (`200`); when `stageId` is omitted a new stage is
created (`201`).

Ordering rules:

- Stages have a 1-based `order` determining their position in the
  pipeline.
- When creating a stage without an `order`, it is placed immediately
  before the `HIRED` stage.
- When an `order` is supplied (on create or update), the other stages'
  orders are adjusted automatically to maintain sequential ordering.
- The `SOURCED` stage's order is locked and cannot be changed.

System stages (`SOURCED`, `APPLIED`, `HIRED`) cannot have their type
changed — only their name can be updated (send `stageId` and `name`
only).




## OpenAPI

````yaml /api-reference/openapi.yaml post /pipelines/stages
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 | `{ "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 |


    ## 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: Webhooks
    description: >-
      Event notifications delivered to your configured webhook endpoint. See the
      top-level `webhooks` section for payloads.
paths:
  /pipelines/stages:
    post:
      tags:
        - Pipelines
      summary: Create or update a pipeline stage
      description: |
        Creates a new stage or updates an existing stage in a pipeline,
        depending on the request body: when `stageId` is present the existing
        stage is updated (`200`); when `stageId` is omitted a new stage is
        created (`201`).

        Ordering rules:

        - Stages have a 1-based `order` determining their position in the
          pipeline.
        - When creating a stage without an `order`, it is placed immediately
          before the `HIRED` stage.
        - When an `order` is supplied (on create or update), the other stages'
          orders are adjusted automatically to maintain sequential ordering.
        - The `SOURCED` stage's order is locked and cannot be changed.

        System stages (`SOURCED`, `APPLIED`, `HIRED`) cannot have their type
        changed — only their name can be updated (send `stageId` and `name`
        only).
      operationId: upsertPipelineStage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertPipelineStageRequest'
            examples:
              createStage:
                summary: Create a new stage
                value:
                  pipelineId: 123
                  name: Technical Interview
                  type: SCREEN
                  order: 3
              updateStage:
                summary: Update an existing stage
                value:
                  pipelineId: 123
                  stageId: 791
                  name: Updated Stage Name
                  type: ASSESSMENT
                  order: 2
              renameSystemStage:
                summary: >-
                  Update only the name of a system stage (SOURCED, APPLIED,
                  HIRED)
                value:
                  pipelineId: 123
                  stageId: 789
                  name: Updated Sourced Stage Name
      responses:
        '200':
          description: |
            Stage updated (request contained a `stageId`). The submitted
            `order` is not echoed in the response body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertPipelineStageResponse'
              examples:
                stageUpdated:
                  summary: Update response
                  value:
                    status: success
                    data:
                      id: 791
                      name: Updated Stage Name
                      type: ASSESSMENT
                      createdAt: '2024-01-15T10:00:00.000Z'
                      updatedAt: '2024-01-15T11:00:00.000Z'
        '201':
          description: |
            Stage created (request contained no `stageId`). The submitted
            `order` is not echoed in the response body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertPipelineStageResponse'
              examples:
                stageCreated:
                  summary: Create response
                  value:
                    status: success
                    data:
                      id: 791
                      name: Technical Interview
                      type: SCREEN
                      createdAt: '2024-01-15T10:00:00.000Z'
                      updatedAt: '2024-01-15T10:00:00.000Z'
        '400':
          description: >
            Validation error.

            HTTP status inferred from the error category; the source
            documentation specifies the body but not the status code.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                invalidStageType:
                  summary: Invalid stage type
                  value:
                    error:
                      code: INVALID_REQUEST
                      type: validation_error
                      message: Stage type is not valid
                invalidOrderRange:
                  summary: Invalid order range
                  value:
                    error:
                      code: INVALID_REQUEST
                      type: validation_error
                      message: Order must be between 1 and 5
                invalidStageId:
                  summary: Invalid stage ID
                  value:
                    error:
                      code: INVALID_REQUEST
                      type: validation_error
                      message: Stage ID is not valid
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    UpsertPipelineStageRequest:
      type: object
      description: |
        Create-or-update request for a pipeline stage. When `stageId` is
        present the existing stage is updated; when it is omitted a new stage
        is created.
      required:
        - pipelineId
      properties:
        pipelineId:
          type: integer
          description: The unique identifier of the pipeline.
          examples:
            - 123
        name:
          type: string
          description: |
            Stage name. The documentation's field table marks this field as
            required, but per its field description it is required when
            creating a stage (no `stageId`) and optional when updating an
            existing stage.
          examples:
            - Technical Interview
        type:
          type: string
          enum:
            - ASSESSMENT
            - SCREEN
            - SHORTLISTED
            - OFFER
            - ONBOARDING
          description: |
            Stage type. The documentation's field table marks this field as
            required, but per its field description it is required when
            creating a stage (no `stageId`) and optional when updating an
            existing stage. Only the five custom types listed here are valid in
            requests; system stages (`SOURCED`, `APPLIED`, `HIRED`) cannot have
            their type changed (omit `type` and send only `stageId` and `name`
            to rename them). An unrecognized value is rejected with
            `INVALID_REQUEST` ("Stage type is not valid").
        stageId:
          type: integer
          description: |
            Stage ID. If provided, updates the existing stage; if omitted,
            creates a new stage.
          examples:
            - 791
        order:
          type: integer
          minimum: 1
          description: |
            Desired 1-based order position. If not provided, new stages are
            placed immediately before the `HIRED` stage. When updating, other
            stages' orders are adjusted automatically to maintain sequential
            ordering. The `SOURCED` stage's order is locked and cannot be
            changed. The documented field table specifies no maximum, but the
            documented validation error reads "Order must be between 1 and 5",
            indicating an upper bound (tied to the pipeline's stage count) is
            enforced in practice; no `maximum` is imposed here.
          examples:
            - 3
    UpsertPipelineStageResponse:
      type: object
      description: |
        Success envelope for stage create (201) and stage update (200) — both
        return the same body shape. The stage's `order` is not echoed.
      required:
        - status
        - data
      properties:
        status:
          type: string
          enum:
            - success
        data:
          $ref: '#/components/schemas/PipelineStage'
    ApiError:
      type: object
      description: Canonical error envelope used by most non-authentication errors.
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/ApiErrorBody'
    PipelineStage:
      type: object
      description: |
        A stage within a hiring pipeline. System stages (`SOURCED`, `APPLIED`,
        `HIRED`) are created automatically with every pipeline, cannot be
        deleted, and cannot have their type changed — only their name is
        editable; additionally the `SOURCED` stage's order is locked. Custom
        stages can be created, updated, and deleted. Stages have a 1-based
        order determining their position in the pipeline, but the order value
        itself is not echoed in any documented response — stages are returned
        in pipeline order.
      required:
        - id
        - name
        - type
        - createdAt
        - updatedAt
      properties:
        id:
          type: integer
          description: Unique identifier of the stage.
          examples:
            - 789
        name:
          type: string
          description: Display name of the stage.
          examples:
            - Phone Screen
        type:
          type: string
          description: |
            Stage type. Observed values: `SOURCED`, `APPLIED`, `HIRED` (system
            stages present in every pipeline); `CUSTOM` (how `GET /pipelines`
            and `GET /pipelines/{pipelineId}` responses represent custom
            stages); and `ASSESSMENT`, `SCREEN`, `SHORTLISTED`, `OFFER`,
            `ONBOARDING` (the specific custom types accepted by
            `POST /pipelines/stages` and echoed in its responses). Because the
            read side reports `CUSTOM` where the write side uses the specific
            custom type, the closed set of response values is unconfirmed and
            no enum is imposed here.
          examples:
            - CUSTOM
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the stage was created.
          examples:
            - '2024-01-15T10:00:00.000Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the stage was last updated.
          examples:
            - '2024-01-15T10:00:00.000Z'
    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
  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.

````