Skip to main content

Overview

Jobs represent open positions that candidates can be screened for. You can create jobs, attach interviews and screening questionnaires, assign ATS jobs, and manage job status. Job Families (read-only) provide a taxonomy layer that groups related jobs. Base URL: https://api.prod.qualifi.hr Authentication: All requests require an x-api-key header.
x-api-key: YOUR_API_KEY
All responses follow the envelope: { "data": { ... }, "meta": { "requestId": "uuid", "timestamp": "ISO-8601" } }.

Create Job

Create a new job posting. Endpoint: POST /qsi/gather/jobs
curl -X POST https://api.prod.qualifi.hr/qsi/gather/jobs \
  -H "x-api-key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Software Engineer",
    "type": "requisition",
    "department": "Engineering",
    "location": ["San Francisco, CA"],
    "workModel": "hybrid"
  }'
{
  "title": "Senior Software Engineer",
  "type": "requisition",
  "department": "Engineering",
  "location": ["San Francisco, CA"],
  "workModel": "hybrid",
  "status": "draft",
  "tags": ["backend", "python"]
}
{
  "data": {
    "job": {
      "id": "job-uuid",
      "title": "Senior Software Engineer",
      "type": "requisition",
      "department": "Engineering",
      "location": ["San Francisco, CA"],
      "workModel": "hybrid",
      "status": "draft",
      "tags": ["backend", "python"],
      "organizationId": "org-uuid",
      "teamId": "team-uuid",
      "createdById": "user-uuid",
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

List Jobs

List jobs with optional filtering and pagination. Endpoint: GET /qsi/gather/jobs
teamId
string
Filter by team UUID
page
number
Page number (default: 1)
pageSize
number
Items per page (default: 50, max: 100)
type
string
Filter by job type
status
string
Filter by job status
department
string
Filter by department
location
string
Filter by location string
Full-text search on job title and description
Pagination: Use page and pageSize query params. The response includes a pagination object with page, pageSize, total, and totalPages fields.
{
  "data": {
    "jobs": [
      {
        "id": "job-uuid",
        "title": "Senior Software Engineer",
        "type": "requisition",
        "department": "Engineering",
        "status": "active",
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
      }
    ],
    "pagination": {
      "page": 1,
      "pageSize": 50,
      "total": 42,
      "totalPages": 1
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Get Job

Retrieve a single job by ID. Endpoint: GET /qsi/gather/jobs/{id}
id
string
required
UUID of the job
teamId
string
Team UUID (used for access scoping)
{
  "data": {
    "job": {
      "id": "job-uuid",
      "title": "Senior Software Engineer",
      "type": "requisition",
      "department": "Engineering",
      "location": ["San Francisco, CA"],
      "workModel": "hybrid",
      "description": "<p>We are looking for a senior engineer...</p>",
      "shortDescription": "Build great things",
      "status": "active",
      "tags": ["backend"],
      "interviewId": "interview-uuid",
      "screeningQuestionnaireId": "questionnaire-uuid",
      "assignedRecruiterId": "user-uuid",
      "jobFamilyIds": ["family-uuid"],
      "knowledgeBaseIds": ["kb-uuid"],
      "organizationId": "org-uuid",
      "teamId": "team-uuid",
      "createdById": "user-uuid",
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}
jobFamilyIds and knowledgeBaseIds are only returned on the single-get response, not the list endpoint.

Update Job

Update job fields (whole-body patch — any subset of optional fields). Endpoint: PATCH /qsi/gather/jobs/{id}
id
string
required
UUID of the job to update
Mutating an ATS-imported job via PATCH returns 409 Conflict. Use the ATS assign endpoint to manage ATS jobs.
{
  "title": "Staff Software Engineer",
  "status": "active"
}
{
  "data": {
    "job": {
      "id": "job-uuid",
      "title": "Staff Software Engineer",
      "status": "active",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Archive Job

Archive (soft-delete) a job. The job remains retrievable with archivedAt set. Endpoint: DELETE /qsi/gather/jobs/{id}
id
string
required
UUID of the job to archive
teamId
string
Team UUID (used for access scoping)
userId
string
UUID of the user performing the archive
{
  "data": {
    "job": {
      "id": "job-uuid",
      "archivedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Unarchive Job

Restore a previously archived job. Endpoint: POST /qsi/gather/jobs/{id}/unarchive
id
string
required
UUID of the job to restore
{
  "data": {
    "job": {
      "id": "job-uuid",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Attach Interview

Attach an interview to a job. Endpoint: PATCH /qsi/gather/jobs/{id}/interview
id
string
required
UUID of the job
{
  "interviewId": "interview-uuid"
}
{
  "data": {
    "job": {
      "id": "job-uuid",
      "interviewId": "interview-uuid",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Attach Screening Questionnaire

Attach a screening questionnaire to a job. Endpoint: PATCH /qsi/gather/jobs/{id}/screening-questionnaire
id
string
required
UUID of the job
{
  "screeningQuestionnaireId": "questionnaire-uuid"
}
{
  "data": {
    "job": {
      "id": "job-uuid",
      "screeningQuestionnaireId": "questionnaire-uuid",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Assign ATS Job

Assign an ATS job to the current team. Endpoint: POST /qsi/gather/jobs/assign-ats
{
  "integrationId": "integration-uuid",
  "externalJobId": "ats-job-123"
}
{
  "data": {
    "job": {
      "id": "job-uuid",
      "title": "Senior Software Engineer",
      "externalId": "ats-job-123",
      "importSource": "greenhouse",
      "teamId": "team-uuid",
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

Unassign Team from Job

Remove the team assignment from a job. Endpoint: DELETE /qsi/gather/jobs/{id}/team-assignment
id
string
required
UUID of the job
teamId
string
Team UUID to unassign
userId
string
UUID of the user performing the unassignment
{
  "data": {
    "success": true
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

JobResponse Field Reference

The following fields may be returned on a job object. Fields marked optional (?) may be absent when not set.
FieldTypeDescription
idstringUUID of the job
titlestringJob title
typestringJob type. One of requisition, pipeline, template
statusstringJob status. One of draft, pending_approval, approved, open, on_hold, closed, filled, cancelled, active, paused, archived. Updates are subject to a transition state-machine (an invalid transition returns 400)
departmentstring?Department
locationstring[]?List of location strings
workModelstring?Work model (remote, hybrid, onsite)
descriptionstring?Full job description (HTML or plain text)
descriptionJsonobject?Structured JSON description
requirementsstring?Requirements text
requirementsJsonobject?Structured JSON requirements
shortDescriptionstring?Auto-generated brief summary (read-only — not settable via the API)
tagsstring[]?List of tags
applyActionstring?Apply button behavior. One of apply_first, interview_first, chat_to_apply
organizationIdstringUUID of the owning organization
teamIdstringUUID of the owning team
externalIdstring?ID in the external ATS
externalSlugstring?Slug in the external ATS
importSourcestring?Name of the ATS that imported this job
interviewIdstring?UUID of the attached interview
meetingIdstring?UUID of the attached meeting
screeningQuestionnaireIdstring?UUID of the attached screening questionnaire
assignedRecruiterIdstring?UUID of the assigned recruiter
createdByIdstringUUID of the user who created the job
createdAtstringISO-8601 creation timestamp
updatedAtstringISO-8601 last-updated timestamp
archivedAtstring?ISO-8601 archive timestamp; omitted from the response when the job is not archived
atsobject?ATS metadata (read-only, see below)
jobFamilyIdsstring[]?Associated job family UUIDs — single-get only
knowledgeBaseIdsstring[]?Associated knowledge base UUIDs — single-get only

ATS Metadata (ats object)

The ats field is read-only and populated from the external ATS. It contains up to 8 sub-fields:
FieldTypeDescription
requisitionIdstring?ATS requisition identifier
hiringManagerstring?Name or ID of the hiring manager in the ATS
recruiterstring?Name or ID of the recruiter in the ATS
headcountnumber?Target headcount
salaryRangeobject?{ min: number, max: number }
employmentTypestring?Employment type as reported by the ATS
openDatestring?ISO-8601 date the requisition was opened
closeDatestring?ISO-8601 date the requisition was closed

Status Limitation

Status transitions are validated by a state-machine. Updating status is only permitted along allowed transitions; an invalid transition returns 400 Bad Request with a message of the form Invalid status transition from '...' to '...'. At creation, only draft, pending_approval, and active are accepted — advanced and terminal states (such as open, on_hold, closed, filled, cancelled, paused, archived) are reachable only via subsequent update transitions.API keys cannot approve jobs. On create, setting status: "approved" always returns 403 Forbidden. On update, transitioning a pending_approval job to approved returns 403 Forbidden. Job approvals must be performed through the Humanly dashboard.

Error Reference

StatusCode / CauseDescription
400Validation error, disallowed field, or invalid status transitionRequest body failed validation, a non-settable field (customFields, crm, ats) was included, or a disallowed status transition was attempted (Invalid status transition from '...' to '...')
401Missing or invalid API keyThe x-api-key header is absent, expired, or does not match any team
403Approval not allowed via API, or acting user not a team memberOn create, setting status: "approved" always returns 403; on update, transitioning a pending_approval job to approved returns 403. Also returned when the acting userId is not a member of the target team
404Not found / wrong team / unknown userThe job UUID does not exist or does not belong to the authenticated team, or the acting userId does not exist
409ATS-imported job mutationAttempted to PATCH an ATS-imported job directly; use the ATS assign endpoint instead
500Internal errorAn unexpected error occurred while processing the request

Job Families

Browse the job family taxonomy associated with your jobs

Interviews

Create and manage interviews to attach to jobs