Credentially Placements API

Placement lifecycle proxy endpoints — assignment of an employee to a location + role within the organisation.

OpenAPI Specification

credentially-placements-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Credentially Public Compliance-packages Placements API
  description: Public API Proxy with Rate Limiting and Audit
  version: 2.0.0
servers:
- url: https://app.credentially.io/gateway
  description: Generated server url
tags:
- name: Placements
  description: Placement lifecycle proxy endpoints — assignment of an employee to a location + role within the organisation.
paths:
  /api/placements/{id}/stage:
    put:
      tags:
      - Placements
      summary: Assign a placement to a stage
      description: 'Idempotent upsert of the placement''s board position. Optional position; 409 on stage disabled or version conflict.


        **Rate Limit:** `remove-placement-stage` (25 req / 1s)'
      operationId: assignStage
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignStageRequest'
        required: true
      responses:
        '200':
          description: Stage assignment created or updated.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '404':
          description: Placement or stage not found in this organisation
        '409':
          description: Target stage disabled or version conflict
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
    delete:
      tags:
      - Placements
      summary: Remove a placement from the stages board
      description: 'Idempotent — 204 whether or not the placement was on the board.


        **Rate Limit:** `remove-placement-stage` (25 req / 1s)'
      operationId: removeFromBoard
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '204':
          description: Placement removed from the board (or was not on it)
        '403':
          description: Token lacks scope, or placement not in caller's organisation
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/{id}:
    get:
      tags:
      - Placements
      summary: Get a placement by public id
      description: '


        **Rate Limit:** `delete-placement` (25 req / 1s)'
      operationId: get
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Placement found
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '401':
          description: Missing or invalid bearer token
        '403':
          description: Token lacks scope, or placement not in caller's organisation
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
    put:
      tags:
      - Placements
      summary: Update a placement's mutable fields
      description: '


        **Rate Limit:** `delete-placement` (25 req / 1s)'
      operationId: update_1
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePlacementRequest'
        required: true
      responses:
        '200':
          description: Placement updated
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '400':
          description: Validation failed
        '403':
          description: Token lacks scope, or placement not in caller's organisation
        '409':
          description: approvalDueDate cannot be changed once approved/started
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
    delete:
      tags:
      - Placements
      summary: Hard-delete a placement
      description: 'Allowed only when PENDING and the start date has not passed; otherwise 409 — use cancel instead.


        **Rate Limit:** `delete-placement` (25 req / 1s)'
      operationId: delete
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '204':
          description: Placement deleted
        '409':
          description: Placement not PENDING, or start date elapsed
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/{id}/stage/prev:
    post:
      tags:
      - Placements
      summary: Move placement to the previous enabled stage
      description: '


        **Rate Limit:** `move-placement-stage` (25 req / 1s)'
      operationId: moveStagePrev
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Moved to the previous stage.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '404':
          description: Placement not found
        '409':
          description: Already at the first stage
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/{id}/stage/next:
    post:
      tags:
      - Placements
      summary: Move placement to the next enabled stage
      description: '


        **Rate Limit:** `move-placement-stage` (25 req / 1s)'
      operationId: moveStageNext
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Moved to the next stage.
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '404':
          description: Placement not found
        '409':
          description: Already at the last stage
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/{id}/cancel:
    post:
      tags:
      - Placements
      summary: Cancel (soft-delete) a placement
      description: 'Sets status to CANCELLED with the supplied reason. Allowed from PENDING or ACTIVE; 409 from COMPLETED.


        **Rate Limit:** `cancel-placement` (25 req / 1s)'
      operationId: cancel
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelPlacementRequest'
        required: true
      responses:
        '204':
          description: Placement cancelled
        '400':
          description: reason missing or blank
        '409':
          description: Placement is COMPLETED — cannot be cancelled
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/{id}/approve:
    post:
      tags:
      - Placements
      summary: Approve a placement
      description: 'Records the calling user as approver + timestamp. Allowed only while PENDING and not already approved.


        **Rate Limit:** `approve-placement` (25 req / 1s)'
      operationId: approve
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Placement approved
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '403':
          description: Token lacks scope, or placement not in caller's organisation
        '409':
          description: Placement not PENDING or already approved
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements:
    get:
      tags:
      - Placements
      summary: List placements (paginated, filterable)
      description: 'Unified filter contract — see the per-parameter docs. Default sort is startDate DESC; override with ?sort=field,dir.


        **Rate Limit:** `list-placements` (100 req / 1s)'
      operationId: list
      parameters:
      - name: employeePublicId
        in: query
        description: Filter by employee public id (singular). Mutually exclusive with employeePublicIds.
        required: false
        schema:
          type: string
          format: uuid
          description: Filter by employee public id (singular). Mutually exclusive with employeePublicIds.
      - name: employeePublicIds
        in: query
        description: Filter by employee public ids (plural, max 50). Mutually exclusive with employeePublicId.
        required: false
        schema:
          type: array
          description: Filter by employee public ids (plural, max 50). Mutually exclusive with employeePublicId.
          items:
            type: string
            format: uuid
            description: Filter by employee public ids (plural, max 50). Mutually exclusive with employeePublicId.
          maxItems: 50
          minItems: 0
      - name: locationPublicIds
        in: query
        description: Filter by location public ids (plural, max 50)
        required: false
        schema:
          type: array
          description: Filter by location public ids (plural, max 50)
          items:
            type: string
            format: uuid
            description: Filter by location public ids (plural, max 50)
          maxItems: 50
          minItems: 0
      - name: jurisdictionPublicIds
        in: query
        description: Filter by jurisdiction public ids (plural, max 50)
        required: false
        schema:
          type: array
          description: Filter by jurisdiction public ids (plural, max 50)
          items:
            type: string
            format: uuid
            description: Filter by jurisdiction public ids (plural, max 50)
          maxItems: 50
          minItems: 0
      - name: rolePublicIds
        in: query
        description: Filter by role public ids (plural, max 50)
        required: false
        schema:
          type: array
          description: Filter by role public ids (plural, max 50)
          items:
            type: string
            format: uuid
            description: Filter by role public ids (plural, max 50)
          maxItems: 50
          minItems: 0
      - name: status
        in: query
        description: Filter by lifecycle status
        required: false
        schema:
          type: string
          description: Filter by lifecycle status
          enum:
          - PENDING
          - ACTIVE
          - COMPLETED
          - CANCELLED
          - PENDING
          - ACTIVE
          - COMPLETED
      - name: complianceStatus
        in: query
        description: Filter by compliance status
        required: false
        schema:
          type: string
          description: Filter by compliance status
          enum:
          - COMPLIANT
          - NOT_COMPLIANT
          - COMPLIANT
          - NOT_COMPLIANT
      - name: startDateFrom
        in: query
        description: Absolute start date floor (inclusive). Mutually exclusive with startsWithinDays.
        required: false
        schema:
          type: string
          format: date
          description: Absolute start date floor (inclusive). Mutually exclusive with startsWithinDays.
      - name: startDateTo
        in: query
        description: Absolute start date ceiling (inclusive). Mutually exclusive with startsWithinDays.
        required: false
        schema:
          type: string
          format: date
          description: Absolute start date ceiling (inclusive). Mutually exclusive with startsWithinDays.
      - name: startsWithinDays
        in: query
        description: Relative start window — N days from today (inclusive). Mutually exclusive with startDateFrom/To.
        required: false
        schema:
          type: integer
          format: int32
          description: Relative start window — N days from today (inclusive). Mutually exclusive with startDateFrom/To.
      - name: page
        in: query
        required: false
        schema:
          type: integer
          format: int32
          default: 0
      - name: size
        in: query
        required: false
        schema:
          type: integer
          format: int32
          default: 20
      - name: sort
        in: query
        required: false
        schema:
          type: array
          items:
            type: string
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Page of placements
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementPageDto'
        '400':
          description: Filter validation failure
        '401':
          description: Missing or invalid bearer token
        '403':
          description: Token lacks required scope
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
    post:
      tags:
      - Placements
      summary: Create a placement
      description: 'Created in PENDING status. jobPositionId is optional (auto-resolved when omitted).


        **Rate Limit:** `list-placements` (100 req / 1s)'
      operationId: create
      parameters:
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePlacementRequest'
        required: true
      responses:
        '201':
          description: Placement created
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementResponseDto'
        '400':
          description: Validation failed
        '401':
          description: Missing or invalid bearer token
        '403':
          description: Token lacks required scope
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
  /api/placements/notes:
    get:
      tags:
      - Placements
      summary: List all placement notes for the organisation (paginated)
      description: '


        **Rate Limit:** `list-placement-notes-org` (100 req / 1s)'
      operationId: listAllNotes
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
          format: int32
          default: 0
      - name: size
        in: query
        required: false
        schema:
          type: integer
          format: int32
          default: 20
      - name: sort
        in: query
        required: false
        schema:
          type: array
          items:
            type: string
      - name: X-API-Version
        in: header
        schema:
          type: string
          default: 2.0.0
          enum:
          - 2.0.0
      responses:
        '200':
          description: Page of notes
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/PlacementNotePageDto'
        '401':
          description: Missing or invalid bearer token
        '403':
          description: Token lacks organisation.placement.view scope
        '429':
          description: Too many requests - the rate limit for this endpoint has been exceeded. Use the Retry-After header to determine when to retry.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying the request.
              schema:
                type: integer
                format: int32
                example: 1
      security:
      - bearer-key: []
components:
  schemas:
    PlacementResponseDto:
      type: object
      properties:
        publicId:
          type: string
          format: uuid
        employeePublicId:
          type: string
          format: uuid
        jobPositionId:
          type: integer
          format: int64
        rolePublicId:
          type: string
          format: uuid
        locationPublicId:
          type: string
          format: uuid
        jurisdictionPublicId:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - PENDING
          - ACTIVE
          - COMPLETED
          - CANCELLED
        complianceStatus:
          type: string
          enum:
          - COMPLIANT
          - NOT_COMPLIANT
        compliancePercentage:
          type: integer
          format: int32
        complianceEvaluationSeq:
          type: integer
          format: int64
        complianceEvaluatedAsOf:
          type: string
          format: date
        startDate:
          type: string
          format: date
        endDate:
          type: string
          format: date
        approvalDueDate:
          type: string
          format: date
        approvedBy:
          type: string
          format: uuid
        approvedAt:
          type: string
          format: date-time
        stagePublicId:
          type: string
          format: uuid
        notesCount:
          type: integer
          format: int32
        latestNotes:
          type: array
          items:
            $ref: '#/components/schemas/PlacementNotePreviewDto'
        createdAt:
          type: string
          format: date-time
        createdBy:
          type: string
          format: uuid
        updatedAt:
          type: string
          format: date-time
        updatedBy:
          type: string
          format: uuid
    UpdatePlacementRequest:
      type: object
      properties:
        rolePublicId:
          type: string
          format: uuid
        locationPublicId:
          type: string
          format: uuid
        startDate:
          type: string
          format: date
        endDate:
          type: string
          format: date
        approvalDueDate:
          type: string
          format: date
      required:
      - locationPublicId
      - rolePublicId
      - startDate
    PlacementNotePreviewDto:
      type: object
      properties:
        content:
          type: string
        createdAt:
          type: string
          format: date-time
    CreatePlacementRequest:
      type: object
      properties:
        employeePublicId:
          type: string
          format: uuid
        jobPositionId:
          type: integer
          format: int64
        rolePublicId:
          type: string
          format: uuid
        locationPublicId:
          type: string
          format: uuid
        startDate:
          type: string
          format: date
        endDate:
          type: string
          format: date
        approvalDueDate:
          type: string
          format: date
        compliancePackageIds:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 50
          minItems: 0
        packageRequirementOverrides:
          type: object
          additionalProperties:
            type: object
            additionalProperties: {}
      required:
      - employeePublicId
      - locationPublicId
      - rolePublicId
      - startDate
    PlacementNotePageDto:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/PlacementNoteResponseDto'
        totalPages:
          type: integer
          format: int32
        totalElements:
          type: integer
          format: int64
        size:
          type: integer
          format: int32
        number:
          type: integer
          format: int32
    PlacementPageDto:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/PlacementResponseDto'
        totalPages:
          type: integer
          format: int32
        totalElements:
          type: integer
          format: int64
        size:
          type: integer
          format: int32
        number:
          type: integer
          format: int32
    AssignStageRequest:
      type: object
      properties:
        stagePublicId:
          type: string
          format: uuid
        position:
          type: integer
          format: int64
      required:
      - stagePublicId
    CancelPlacementRequest:
      type: object
      properties:
        reason:
          type: string
          maxLength: 2000
          minLength: 0
      required:
      - reason
    PlacementNoteResponseDto:
      type: object
      properties:
        publicId:
          type: string
          format: uuid
        placementPublicId:
          type: string
          format: uuid
        employeePublicId:
          type: string
          format: uuid
        locationName:
          type: string
        roleName:
          type: string
        content:
          type: string
        createdAt:
          type: string
          format: date-time
        createdBy:
          type: string
          format: uuid
        createdByName:
          type: string
        createdByJobRole:
          type: string
        updatedAt:
          type: string
          format: date-time
        updatedBy:
          type: string
          format: uuid
  securitySchemes:
    bearer-key:
      type: http
      scheme: bearer
      bearerFormat: JWT