Purple ATS API Documentation
Machine-readable OpenAPI 3.0 specification: https://marketplace.moveworks.com/api/purple-suite/ats/openapi.json
The consolidated all-apps document at https://marketplace.moveworks.com/api/purple-suite/openapi.json can be narrowed to this app with ?apps=ats, or combined with other apps comma-separated (e.g. ?apps=ats,itsm).
Overview
Endpoints
GET /api/purple-suite/ats/requisitions
List Purple ATS job requisitions
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01". |
$select | query | string | no | Comma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
RequisitionidstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/ats/requisitions
Open a job requisition
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Requisition
idstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonRequisitionidstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
GET /api/purple-suite/ats/requisitions/{id}
Get requisition
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonRequisitionidstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/ats/requisitions/{id}
Delete requisition
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/ats/requisitions/{id}
Update requisition
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Requisition
idstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonRequisitionidstringtitlestringdepartmentstringstatusstringheadcountintegerhiringManagerstring — Hiring manager email. Alias: hiring_manager (snake_case accepted).createdBystring — Email of the user who created this requisition. Alias: created_by (snake_case accepted).responsibilitiesstring — Short prose description of what the role does.required_skillsarray — Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).Skills the role requires, each with a target proficiency. Alias: requiredSkills (camelCase accepted).array of:
skillstringproficiencystring
levelstring — Seniority label — e.g. IC1/IC2/IC3/Sr/Manager/Director, or any free-text level.target_role_forarray — IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).IDs of requisitions/roles this one is a common next step from (career pathing). Alias: targetRoleFor (camelCase accepted).array of:
string (example:
"REQ-0001")openedAtstringcreatedAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/ats/candidates
List Purple ATS job applicants
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01". |
$select | query | string | no | Comma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
CandidateidstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/ats/candidates
Add an applicant to the hiring pipeline
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Candidate
idstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
Responses
201- Created
application/jsonCandidateidstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
GET /api/purple-suite/ats/candidates/{id}
Get candidate
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonCandidateidstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/ats/candidates/{id}
Delete candidate
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/ats/candidates/{id}
Update a candidate record
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Candidate
idstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
Responses
200- Updated
application/jsonCandidateidstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
404- Not found
POST /api/purple-suite/ats/candidates/{id}/advance
Advance a candidate to the next hiring stage
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
statusstring — Target stage to advance to. Omit to auto-advance to the next stage. Alias: stage (snake_case/legacy accepted).notesstring
Responses
200- Candidate advanced
application/jsonCandidateidstringfirstNamestring — Alias: first_name (snake_case accepted).lastNamestring — Alias: last_name (snake_case accepted).emailstringphonestringrequisitionIdstring — Alias: requisition_id (snake_case accepted).statusstring — Current pipeline stage. Alias: stage (accepted on create/update).sourcestringresumeUrlstring — Alias: resume_url (snake_case accepted).appliedAtstringstageHistoryarrayarray of:
statusstringnotesstringrecordedAtstring
createdAtstringupdatedAtstring
400- Invalid stage value
404- Candidate not found
422- Stage transition not allowed (rejected/withdrawn/hired/backwards move)
POST /api/purple-suite/ats/candidates/{id}/generate-offer
Generate a draft offer for a candidate
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
salarynumber — Base salary. Alias: baseSalary (camelCase accepted). Stored as baseSalary on the created Offer document.equitystring — Equity grant string (e.g. '0.25%').start_datestring — Proposed start date. Alias: startDate (camelCase accepted).expires_atstring — Offer expiry date. Alias: expiresAt (camelCase accepted).sentAtstring — Timestamp when offer was sent, if already dispatched.
Responses
201- Offer created
application/jsonOfferidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
404- Candidate not found
422- Candidate already hired or already has an active offer
GET /api/purple-suite/ats/interviews
List Purple ATS candidate interviews
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01". |
$select | query | string | no | Comma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
InterviewidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/ats/interviews
Create interview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Interview
idstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonInterviewidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
GET /api/purple-suite/ats/interviews/{id}
Get interview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonInterviewidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/ats/interviews/{id}
Delete interview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/ats/interviews/{id}
Update interview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Interview
idstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonInterviewidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).interviewerstringscheduledAtstring — Alias: scheduled_at (snake_case accepted).typestringstatusstringfeedbackstringratingintegercreatedAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/ats/offers
List Purple ATS job offers
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01". |
$select | query | string | no | Comma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
OfferidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/ats/offers
Create offer
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Offer
idstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
Responses
201- Created
application/jsonOfferidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
GET /api/purple-suite/ats/offers/{id}
Get offer
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonOfferidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/ats/offers/{id}
Delete offer
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/ats/offers/{id}
Update offer
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Offer
idstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
Responses
200- Updated
application/jsonOfferidstringcandidateIdstring — Alias: candidate_id (snake_case accepted).requisitionIdstring — Alias: requisition_id (snake_case accepted).baseSalarynumber — Base salary amount. Alias: salary (accepted on create/update).equitystringstartDatestring — Alias: start_date (snake_case accepted).statusstringsentAtstring — Timestamp when the offer was dispatched to the candidate. Client-settable.expiresAtstring — Alias: expires_at (snake_case accepted).createdAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/ats/job-postings
List Purple ATS job postings
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01". |
$select | query | string | no | Comma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
JobPostingidstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/ats/job-postings
Create job posting
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
JobPosting
idstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
Responses
201- Created
application/jsonJobPostingidstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
GET /api/purple-suite/ats/job-postings/{id}
Get job posting
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonJobPostingidstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/ats/job-postings/{id}
Delete job posting
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/ats/job-postings/{id}
Update job posting
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
JobPosting
idstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
Responses
200- Updated
application/jsonJobPostingidstringrequisitionIdstring — Alias: requisition_id (snake_case accepted).titlestringdepartmentstringdescriptionstringlocationstringtypestringstatusstringapplicantCountinteger — Running applicant count. Defaults to 0 on create; may be set by the client and is not server-managed.postedAtstring — Alias: posted_at (snake_case accepted).createdAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/ats/referrals
List Purple ATS employee referrals
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Responses
200- Referral list
application/jsonreferralsarrayarray of:
object
totalCountintegerstatusCountsobject
POST /api/purple-suite/ats/referrals
Submit an employee referral
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
referrer_emailstring requiredcandidate_namestring requiredcandidate_emailstring requiredpositionstring
Responses
200- Referral submitted
application/jsonsuccessbooleanreferralobjectidstringreferrer_emailstringcandidate_namestringcandidate_emailstringpositionstringstatusstringcreated_atstring
400- Missing required fields