# Greenhouse Harvest Documentation > Documentation for Greenhouse Harvest ## Guides - [Rate Limiting](https://harvestdocs.greenhouse.io/docs/api-rate-limiting.md): This guide explains our API rate limiting policy to help you build reliable and efficient applications. Understanding these limits is crucial for preventing service disruptions - [Authentication](https://harvestdocs.greenhouse.io/docs/authentication.md): This guide explains how to authenticate to the Greenhouse Harvest v3 API. - [List endpoints](https://harvestdocs.greenhouse.io/docs/list-endpoints.md) - [Pagination](https://harvestdocs.greenhouse.io/docs/pagination.md): Harvest v3 uses **cursor-based pagination** for list endpoints. - [Handling scope changes](https://harvestdocs.greenhouse.io/docs/handling-scope-changes.md): A guide for integration partners on how to request scope updates and how these changes impact existing OAuth tokens and user authorization flows. - [Integrating as a Greenhouse Harvest Partner (OAuth 2.0 Auth Code Grant Guide)](https://harvestdocs.greenhouse.io/docs/harvest-partner-oauth.md): This guide outlines how partner integrations must connect to the Greenhouse Harvest V3 API using the standard OAuth 2.0 Authorization Code Grant flow. You'll learn how to get authorization from mutual customers, obtain access tokens, keep the connection active, and handle common errors. - [Overview and philosophy](https://harvestdocs.greenhouse.io/docs/overview-and-philosophy.md) - [Standardizations](https://harvestdocs.greenhouse.io/docs/standardizations.md) - [READ Endpoint Migration Guide](https://harvestdocs.greenhouse.io/docs/step-by-step-migration-instructions.md) - [WRITE Endpoint Migration Guide](https://harvestdocs.greenhouse.io/docs/write-endpoint-migration-guide.md) ## API Reference - [Generate token](https://harvestdocs.greenhouse.io/reference/generate-token.md) - [Introspect token](https://harvestdocs.greenhouse.io/reference/introspect-token.md): Introspect an OAuth 2.0 token to determine its active status and retrieve its associated metadata. - [generate access_token](https://harvestdocs.greenhouse.io/reference/post_auth-token.md) - [List application stages](https://harvestdocs.greenhouse.io/reference/get_v3-application-stages.md): Application stages are the rows that make up a candidate's stage history on an application — one row per interview stage the application has occupied, with `entered_at` and `exited_at` timestamps. An application_stage is the join between an application and a `job_interview_stage`; the row with `exited_at` null (and `current: true`) is the candidate's current stage on that application. Filter with `application_ids` to retrieve the stage history for specific applications, or `job_interview_stage_ids` to find every application that has touched a given stage. This endpoint is the canonical source for stage-history reporting; partner BI integrations typically treat it as the fact table. - [Delete application](https://harvestdocs.greenhouse.io/reference/delete_v3-applications-id.md): Permanently delete a single application, along with its interview stages, scorecards, rejection details, and prospect details. The parent candidate (person) is left intact along with any other applications they have. This action cannot be undone; consider `reject` if you want to record the outcome instead. - [List applications](https://harvestdocs.greenhouse.io/reference/get_v3-applications.md): Applications represent a candidate's journey on a specific job — the bridge between a candidate (person) and a job. Each candidate can have one application per job (and prospect applications can be jobless or attached to multiple prospective jobs). Scope the list with one of the parent-id arrays — `candidate_ids`, `job_ids`, `job_post_ids`, `source_ids`, `referrer_ids`, `stage_ids`, or `prospective_job_ids` — to filter by the matching foreign key. Pass `ids` directly to fetch specific applications by id (max 50 per request). - [Update application](https://harvestdocs.greenhouse.io/reference/patch_v3-applications-id.md): Patch attribution and metadata fields on an existing application (source, referrer, recruiter, coordinator, prospect pool/stage, rejection date, custom fields). Stage transitions are not handled here — use the `move`, `reject`, `unreject`, `hire`, or `convert_to_candidate` endpoints to advance the application's lifecycle. Only keys present in the request body are modified; omitted keys are left untouched. - [Convert a prospect to a candidate](https://harvestdocs.greenhouse.io/reference/post_v3-applications-id-convert-to-candidate.md): Promote a prospect application to a candidate application on a specific job. `job_id` is required and the prospect must already be associated with that job (or attached at the prospect pool level). Pass `to_job_interview_stage_id` to place the new candidate application on a specific interview stage; omit it to land them on the job's first stage. The prospect application's status transitions to `converted` and a new candidate application is returned in the response. - [Mark an application as hire](https://harvestdocs.greenhouse.io/reference/post_v3-applications-id-hire.md): Mark an application as hired and close out the matching opening on the job. Pass `opening_id` to identify which opening on the job the candidate fills (required when the job has more than one open opening); `start_date` records the candidate's start date; `close_reason_id` is the reason the opening is being closed (typically the `Hire` close reason). The application's status transitions to `hired`. - [Move an application to a different stage within the same job or transfer to another job](https://harvestdocs.greenhouse.io/reference/post_v3-applications-id-move.md): Advance the candidate to a new interview stage. `from_stage_id` is required and must match the candidate's current stage — it acts as a guard against stale move requests. Provide `to_stage_id` to move within the same job, or `to_job_id` to transfer the application onto a different job (the candidate lands on that job's first interview stage). A successful move fires any configured stage transition rules, including automated emails sent from `email_from_user_id` (or a global address when supplied via Greenhouse configuration). - [Reject application](https://harvestdocs.greenhouse.io/reference/post_v3-applications-id-reject.md): Reject an application and record the reason. `rejection_reason_id` is required (look up valid reasons via `GET /v3/rejection_reasons`); optional `notes` capture context on the rejection. Pass a `rejection_email` object to send the candidate a templated rejection email — either immediately or scheduled for a future `send_email_at` timestamp. Custom field values on the application can be set in the same call via `custom_fields`. - [Unreject application](https://harvestdocs.greenhouse.io/reference/post_v3-applications-id-unreject.md): Reverse a rejection, putting the application back into the in-process state on the stage it was rejected from. The previously recorded rejection reason and notes are cleared. Use this when a candidate is brought back into consideration after being rejected. - [Create application](https://harvestdocs.greenhouse.io/reference/post_v3-applications.md): Create a new application for an existing candidate. The body accepts one of two shapes: a candidate application (requires `candidate_id` + `job_id`) places the candidate at the job's first interview stage (or `initial_stage_id` when supplied); a prospect application (requires `candidate_id` + `prospect: true`) creates a prospect, optionally attached to one or more jobs via `job_ids`, a prospect pool via `prospect_pool_id` + `prospect_pool_stage_id`, or prospective department/office. To create a candidate and their first application in a single call, use `POST /v3/candidates` with a nested `application` object. - [Delete applied candidate tag](https://harvestdocs.greenhouse.io/reference/delete_v3-applied-candidate-tags-id.md): Detach a single tag from a candidate. The `{id}` here is the applied-tag row id (returned by list/create), not the candidate id or the candidate_tag id; resolve it via `GET /v3/applied_candidate_tags?candidate_ids=` when you only have the candidate. The tag itself remains in the organization's dictionary — use `DELETE /v3/candidate_tags/{id}` to retire the tag entirely. - [List applied candidate tags](https://harvestdocs.greenhouse.io/reference/get_v3-applied-candidate-tags.md): Applied candidate tags are the join rows between candidates and the organization's candidate-tag dictionary — one row per (candidate, tag) pair. Filter with `candidate_ids` to list every tag on a set of candidates, or `candidate_tag_ids` to list every candidate carrying a set of tags. The tag names themselves live on `/v3/candidate_tags`; this endpoint only exposes the foreign keys. - [Create applied candidate tag](https://harvestdocs.greenhouse.io/reference/post_v3-applied-candidate-tags.md): Apply an existing tag to a candidate. Both `candidate_id` and `candidate_tag_id` are required; the tag must already exist in the organization's candidate-tag dictionary (create it via `POST /v3/candidate_tags` first if needed). Applying a tag a candidate already has is idempotent at the data level but returns a 422 on duplicate. This replaces V1's batch `PUT /v1/candidates/{id}/tags` workflow — to attach multiple tags, issue one POST per tag. - [List approval flows](https://harvestdocs.greenhouse.io/reference/get_v3-approval-flows.md): Approval flows are the multi-step approval definitions attached to a job or to a candidate's offer. Each flow has an ordered list of approver groups (`/v3/approver_groups?approval_flow_ids=`), and each group holds the individual approvers (`/v3/approvers?approver_group_ids=`); a flow resolves as `approved` only when every group resolves as approved. Filter by `approval_type` to scope to job-opening, job-offer, or candidate-offer flows, and by `job_ids` or `offer_ids` to scope to specific parents. Default approval flows that serve as the prototype for new jobs are not returned here. - [Update approval flow](https://harvestdocs.greenhouse.io/reference/patch_v3-approval-flows-id.md): Toggle whether an existing approval flow is `sequential` (approver groups resolve one at a time in `sort_order`) or parallel (all groups activate at once). The flow must be in `pending` status — once it is `approved` or `rejected` the request returns 422. To restructure the groups themselves use `PUT /v3/approval_flows/{id}/replace_approver_groups`; to swap one user within a group use `PUT /v3/approver_groups/{id}/replace_approver`. - [Request approvals](https://harvestdocs.greenhouse.io/reference/post_v3-approval-flows-id-request-approvals.md): Start an existing `pending` approval flow by emailing its initial approver(s) and recording who requested the approvals. This is the V3 equivalent of the in-app "Request Approval" button: until it is called, an approval flow's approver groups exist but no one is asked to approve. The flow must be startable — every group already populated, no resolved approvers yet, and (for `offer_candidate` flows) an `offer_id` set — otherwise the call returns 422. Pass `requested_by_user_id` to record someone other than the calling user as the requester; the same user is shown as the sender on the approval emails. Returns 204 with no body. - [Create approval flow](https://harvestdocs.greenhouse.io/reference/post_v3-approval-flows.md): Create a multi-step approval flow on a job (and optionally a specific offer), seeded with the supplied approver groups. Each job allows at most one flow per `approval_type`: one `open_job` flow gating job opening, one `offer_job` flow gating offer creation, and one `offer_candidate` prototype on the job plus one `offer_candidate` flow per offer (set `offer_id` for the latter). The new flow is created in `pending` status with no emails sent; call `POST /v3/approval_flows/{id}/request_approvals` to actually start it. Each approver entry may identify a user by `user_id`, `email`, or `employee_id`, but the same user cannot appear in more than one group of the same flow. - [Replace approver groups](https://harvestdocs.greenhouse.io/reference/put_v3-approval-flows-id-replace-approver-groups.md): Wholesale-replace the ordered tiers of approvers on an existing approval flow — the V3 equivalent of rebuilding the flow's structure from an external HRIS. The flow must be in `pending` status; resolved (approved or rejected) flows cannot be modified. The new array's index becomes each group's `sort_order`, each approver entry must identify a user by `user_id`, `email`, or `employee_id`, and the same user cannot appear in more than one group. To swap a single approver inside a group without touching the rest of the flow use `PUT /v3/approver_groups/{id}/replace_approver`; to flip the flow between sequential and parallel use `PATCH /v3/approval_flows/{id}`. - [List approver groups](https://harvestdocs.greenhouse.io/reference/get_v3-approver-groups.md): Approver groups are the ordered tiers of approvers inside a single approval flow on a job or offer. Each group has its own `approvals_required` threshold (e.g., "any 1 of 3" or "all 4") and resolves as approved once that many of its members approve, or as rejected once enough members reject. Groups with a lower `sort_order` must resolve as approved before later groups become actionable. Filter to a specific flow with `approval_flow_ids` and look up the individual people in each group via `/v3/approvers?approver_group_ids=`. To restructure the tiers themselves, use `PUT /v3/approval_flows/{id}/replace_approver_groups`; to swap one person within a group, use `PUT /v3/approver_groups/{id}/replace_approver`. - [Replace approver](https://harvestdocs.greenhouse.io/reference/put_v3-approver-groups-id-replace-approver.md): Swap one approver in an approver group for another user without rebuilding the rest of the approval flow — the V3 replacement for V1 `PUT /v1/approval_flows/{id}/approver_groups/{id}/replace_approver`. The `remove_user_id` must currently be an unresolved approver on this group; resolved groups (already approved or rejected) cannot be modified. The `add_user_id` must be a different user, must not already be an approver anywhere else in the same approval flow, and must have read access to the underlying job or offer. To replace the entire set of groups on a flow, use `PUT /v3/approval_flows/{id}/replace_approver_groups` instead. - [List approvers](https://harvestdocs.greenhouse.io/reference/get_v3-approvers.md): Approvers are the individual users assigned to approve a job, offer, or other approvable resource. Each approver belongs to an approver group (`/v3/approver_groups`), and the group in turn belongs to an approval flow (`/v3/approval_flows`); the same user appears as multiple approvers when they are assigned across multiple flows. Filter by `status` to find pending (`waiting`, `due`) vs. resolved (`approved`, `rejected`) approvers, and by `user_ids` or `approver_group_ids` to scope to specific people or groups. - [Delete attachment](https://harvestdocs.greenhouse.io/reference/delete_v3-attachments-id.md): Permanently remove an attachment from its application. The underlying file is also cleaned up if no other attachment references it. Deleting a `resume` clears the application's resume score and parsed-resume index entry; this action cannot be undone. - [List attachments](https://harvestdocs.greenhouse.io/reference/get_v3-attachments.md): Attachments are files associated with an application — resumes, cover letters, take-home tests, offer documents, e-signed agreements, and other supporting documents. Each attachment belongs to one application; filter by `application_ids` or `candidate_ids` to scope results to a specific pipeline. The `url` returned for each attachment is a time-limited download link that expires after seven days, so refetch the attachment whenever you need a fresh URL. - [Create attachment](https://harvestdocs.greenhouse.io/reference/post_v3-attachments.md): Attach a file to an existing application. Supply the bytes inline as base64-encoded `content`, or point Greenhouse at a publicly fetchable `url` and we will download the file on your behalf — exactly one of the two is required. `type` controls how the attachment is classified in Greenhouse (resume, cover_letter, offer_letter, etc.); uploading a `resume` or `cover_letter` replaces any prior attachment of that type by reclassifying the existing one as `other`. Filenames are validated against the organization's blocklisted-extensions list (for example, `.html` is rejected for `take_home_test`). - [Bulk delete blocked spam sources](https://harvestdocs.greenhouse.io/reference/delete_v3-blocked-spam-sources-bulk.md): Removes multiple blocked spam sources in a single request, identified by id. Future applications from the previously blocked sources will no longer be auto-rejected; applications already rejected against the deleted entries remain rejected. Per-item failures are reported in the response without aborting the rest of the batch. - [Delete blocked spam source](https://harvestdocs.greenhouse.io/reference/delete_v3-blocked-spam-sources-id.md): Removes a blocked spam source. Future applications from the previously blocked IP, CIDR range, email address, or domain will no longer be auto-rejected at intake; applications already rejected against this entry remain rejected and must be reinstated through the usual candidate workflows. - [List blocked spam sources](https://harvestdocs.greenhouse.io/reference/get_v3-blocked-spam-sources.md): Lists the IP addresses, CIDR ranges, email addresses, and email domains the organization has blocked from submitting applications. Entries are managed under Configure > Real Talent > Spam in the Greenhouse UI and via this resource; applications arriving from a matching source are auto-rejected at intake with the reason `Rejected by organization blocklist`. Requires the Real Talent spam blocklist product flag to be enabled on the organization; without it the endpoint returns 403. - [Bulk update blocked spam sources](https://harvestdocs.greenhouse.io/reference/patch_v3-blocked-spam-sources-bulk.md): Updates the `note` on multiple blocked spam sources in a single request. Each item in `data` must include the `id` of the target entry; `source_type` and `value` cannot be changed via this endpoint. Per-item failures are reported in the response without aborting the rest of the batch. - [Update blocked spam source](https://harvestdocs.greenhouse.io/reference/patch_v3-blocked-spam-sources-id.md): Updates the `note` on a blocked spam source. `source_type` and `value` are immutable on this endpoint — to change either, delete the entry and create a new one. - [Bulk create blocked spam sources](https://harvestdocs.greenhouse.io/reference/post_v3-blocked-spam-sources-bulk.md): Adds multiple blocked spam sources in a single request, typically used to sync the blocklist from an external security tool. Each item in `data` is validated and persisted independently — per-item failures are reported in the response without aborting the rest of the batch. - [Create blocked spam source](https://harvestdocs.greenhouse.io/reference/post_v3-blocked-spam-sources.md): Adds a new IP address, CIDR range, email address, or email domain to the organization's spam blocklist. Once added, future applications arriving from a matching source are auto-rejected at intake; the entry does not retroactively reject existing applications. The combination of `source_type` and `value` must be unique within the organization, IP and CIDR values must be well-formed, and a small set of common consumer email domains is protected from being blocked. - [Bulk request (single)](https://harvestdocs.greenhouse.io/reference/get_v3-bulk-requests-bulk-action-uuid.md): Retrieve a single bulk request, including the per-row success and failure result files. Each call mints fresh short-lived (5 minute) S3 URLs for `success_results_url` and `failure_results_url`; re-fetch this endpoint to get new URLs once they expire. The bulk request record itself, along with its result files, is deleted at `expires_at`. - [Bulk requests](https://harvestdocs.greenhouse.io/reference/get_v3-bulk-requests.md): Bulk requests track the asynchronous bulk operations submitted to Harvest V3. Each time a partner hits a `/v3//bulk` endpoint, Greenhouse creates a bulk request, returns its `bulk_action_uuid`, and dispatches each row in the `data` array to the matching single-resource endpoint in its own Sidekiq job. Use this endpoint to enumerate in-flight or recently completed bulk jobs for the calling client; use the single-bulk-request endpoint to retrieve per-row success and failure result files. - [List candidate attribute types](https://harvestdocs.greenhouse.io/reference/get_v3-candidate-attribute-types.md): Candidate attribute types are the structured attribute dictionary on a job — the per-job catalogue of evaluable traits (e.g. `JavaScript`, `Leadership`, `Years of experience`) that get rated on scorecards and that AI matching uses to score candidate fit. Distinct from custom fields: custom fields are free-form data attached to a candidate, while attribute types are typed, job-scoped traits whose values live on `job_candidate_attributes` (the job-level catalogue entry), `focus_candidate_attributes` (which attributes a given interview kit focuses on), and `scorecard_candidate_attributes` (the interviewer's rating of a candidate on each attribute). Today this endpoint is site-admin-only. - [Delete candidate education](https://harvestdocs.greenhouse.io/reference/delete_v3-candidate-educations-id.md): Remove a single education entry from a candidate's profile. Because V3 has no update endpoint for educations, corrections are made by deleting the stale entry and creating a new one. Deleting the candidate's `latest: true` entry causes Greenhouse to recompute `latest` on the remaining entries. - [List candidate educations](https://harvestdocs.greenhouse.io/reference/get_v3-candidate-educations.md): Candidate educations are the school/degree/discipline entries on a candidate's profile — one row per education entry. V3 flattens what V1 nested under `/v1/candidates/{id}/educations`; filter with `candidate_ids` to retrieve a single candidate's full education history. School, degree, and discipline are stored as references to custom-field option ids — resolve the display names via `/v3/custom_field_options`. Use `latest=true` to retrieve only each candidate's most recent education. - [Create candidate education](https://harvestdocs.greenhouse.io/reference/post_v3-candidate-educations.md): Add a new education entry to a candidate's profile. `candidate_id` is required; school, degree, and discipline are optional but must reference existing custom-field option ids (look these up via `GET /v3/custom_field_options` for the org's `school_name`, `degree`, and `discipline` custom fields, or create new options via `POST /v3/custom_field_options` first). Provide either `start_date`/`end_date` as ISO 8601 dates, or the month/year component pairs when only that granularity is known — the Greenhouse UI displays month-and-year regardless. Greenhouse recomputes `latest` automatically. - [Delete candidate employment](https://harvestdocs.greenhouse.io/reference/delete_v3-candidate-employments-id.md): Remove a single employment entry from a candidate's profile. Because V3 has no update endpoint for employments, corrections to `company_name`, `title`, or dates are made by deleting the stale entry and creating a new one. Deleting the candidate's `latest: true` entry causes Greenhouse to recompute `latest` on the remaining entries (and the parent candidate's `company` and `title` will update to follow). - [List candidate employments](https://harvestdocs.greenhouse.io/reference/get_v3-candidate-employments.md): Candidate employments are the work history entries on a candidate's profile — one row per employer/title the candidate has held. V3 flattens what V1 nested under `/v1/candidates/{id}/employments`; filter with `candidate_ids` to retrieve a single candidate's full work history. `company_name` and `title` are free-text strings (unlike candidate educations, they are not backed by custom-field option ids). Use `latest=true` to retrieve only each candidate's most recent employment, which mirrors the `company` and `title` shown on the parent candidate record. - [Create candidate employment](https://harvestdocs.greenhouse.io/reference/post_v3-candidate-employments.md): Add a new work history entry to a candidate's profile. `candidate_id`, `company_name`, `title`, and `start_date` are required; `company_name` and `title` are free-text strings (no custom-field option lookup is needed). Omit `end_date` to record the entry as the candidate's current job — Greenhouse will then recompute the `latest` flag across the candidate's employments, with the current job winning over any historical entries. - [Delete candidate tag](https://harvestdocs.greenhouse.io/reference/delete_v3-candidate-tags-id.md): Remove a tag from your organization's candidate-tag dictionary. The tag is also removed from every candidate it was applied to — there's no need to delete the corresponding `applied_candidate_tags` rows first. Use this for retiring tag taxonomies; to detach a single candidate from a tag without retiring the tag, use `DELETE /v3/applied_candidate_tags/{id}` instead. - [List candidate tags](https://harvestdocs.greenhouse.io/reference/get_v3-candidate-tags.md): Candidate tags are the org-wide library of tag names available to apply to candidates (e.g. `engineering`, `referral`, `2026-grad`). This endpoint returns the dictionary of available tags — to see which tags are applied to which candidates, use `/v3/applied_candidate_tags` instead. A typical integration flow creates a tag here (POST) and then attaches it to candidates via `POST /v3/applied_candidate_tags`. - [Create candidate tag](https://harvestdocs.greenhouse.io/reference/post_v3-candidate-tags.md): Add a new tag to your organization's candidate-tag dictionary. `name` is required and must be unique within the organization (case sensitive); creating a tag with an existing name returns a 422. Creating a tag here does not attach it to any candidate — use `POST /v3/applied_candidate_tags` with the returned tag id to apply it. - [Delete candidate](https://harvestdocs.greenhouse.io/reference/delete_v3-candidates-id.md): Permanently delete a candidate and all of their applications, attachments, scorecards, notes, and other associated records. This action cannot be undone; for GDPR or right-to-be-forgotten workflows prefer the anonymize endpoint, which preserves aggregate hiring data while removing personally identifiable information. - [List candidates](https://harvestdocs.greenhouse.io/reference/get_v3-candidates.md): Candidates are the people your organization is recruiting — both active applicants and prospects. A candidate record holds the personal profile (names, contact methods, tags, custom fields) and is the parent of one or more applications, each of which represents the candidate's journey on a specific job. Use the `ids` query parameter to fetch a single candidate by id; nested data (applications, attachments, educations, employments) lives on its own resource endpoint in V3. - [Anonymize candidates](https://harvestdocs.greenhouse.io/reference/patch_v3-candidates-id-anonymize.md): Anonymize selected categories of personally identifiable data on a candidate (for GDPR, CCPA, or other right-to-be-forgotten requests). The `fields` array selects which data groups to scrub — see the schema enum for the full set (e.g. `full_name`, `email_addresses`, `phone_numbers`, `attachments`, `notes`, `scorecards_and_interviews`). Anonymization is irreversible and runs asynchronously when the selected scope is large; the candidate's hiring activity remains intact for reporting. - [Update candidate](https://harvestdocs.greenhouse.io/reference/patch_v3-candidates-id.md): Patch an existing candidate's profile fields. Only the keys included in the request body are modified; omitted keys are left untouched. Array fields (`phone_numbers`, `addresses`, `email_addresses`, `website_addresses`, `social_media_addresses`, `tags`, `linked_user_ids`, `custom_fields`) replace the existing collection wholesale — send the full desired list, not a delta. Setting `is_private` to `true` restricts the candidate to users with `View Private Candidates` access. - [Merge candidates](https://harvestdocs.greenhouse.io/reference/post_v3-candidates-id-merge.md): Merge two candidate profiles by collapsing the candidate identified by `secondary_candidate_id` into the candidate at `{id}`. The primary candidate (`{id}`) survives and absorbs the secondary's applications, attachments, notes, tags, and other history; the secondary record is deleted. Use this to resolve duplicate candidates created across multiple sources or job applications. - [Create candidate](https://harvestdocs.greenhouse.io/reference/post_v3-candidates.md): Create a new candidate profile in your organization. `first_name` and `last_name` are required; all other profile fields are optional. Pass a nested `application` object to simultaneously create the candidate's first application — supply a `job_id` to create an applicant, or a `prospect_pool_id` (and omit `job_id`) to create a prospect. Tag names that don't yet exist on the organization are created on the fly. - [List close reasons](https://harvestdocs.greenhouse.io/reference/get_v3-close-reasons.md): Close reasons are the organization-defined dictionary of outcomes recorded when an opening is closed (e.g. `Hire - New Headcount`, `Hire - Backfill`, `On Hold`, `Not Filling`). Each closed `opening` references a single close reason via `close_reason_id`; resolve the human-readable label here. Customized per organization under Configure > Custom Options > Close Reasons for Job Openings, so the available set varies between Greenhouse accounts. Distinct from `rejection_reasons`, which apply to candidate applications rather than to openings. - [Delete custom field department](https://harvestdocs.greenhouse.io/reference/delete_v3-custom-field-departments-id.md): Remove a department from a custom field's visibility scope. Deleting the last custom_field_department row for a field restores its default behavior of being visible to every department. - [List custom field departments](https://harvestdocs.greenhouse.io/reference/get_v3-custom-field-departments.md): A custom_field_department restricts a custom field's visibility to a single department, so the field only appears on jobs, offers, or candidates whose department matches. A custom field with no rows in this list is visible to every department. Filter by `custom_field_ids` to see which departments a given field is scoped to, or by `department_ids` to see which fields are scoped to a given department. - [Create custom field department](https://harvestdocs.greenhouse.io/reference/post_v3-custom-field-departments.md): Restrict a custom field's visibility to one additional department. Each call adds one (custom_field_id, department_id) pair; repeat the call for each department the field should appear under. Once any custom_field_department rows exist for a field, it stops being visible to departments outside the list. - [Delete custom field office](https://harvestdocs.greenhouse.io/reference/delete_v3-custom-field-offices-id.md): Remove an office from a custom field's visibility scope. Deleting the last custom_field_office row for a field restores its default behavior of being visible to every office — useful when an org pivots to remote/hybrid and stops scoping fields by location. - [List custom field offices](https://harvestdocs.greenhouse.io/reference/get_v3-custom-field-offices.md): A custom_field_office restricts a custom field's visibility to a single office, so the field only appears on jobs, openings, or offers whose office matches. A custom field with no rows in this list is visible to every office — the right default for remote-first or single-office orgs that don't scope fields by location. Filter by `custom_field_ids` to see which offices a given field is scoped to, or by `office_ids` to see which fields are scoped to a given office. Office scoping composes with `/v3/custom_field_departments`: a field carrying both kinds of rows is only visible where both an office and department match. - [Create custom field office](https://harvestdocs.greenhouse.io/reference/post_v3-custom-field-offices.md): Restrict a custom field's visibility to one additional office. Each call adds one (custom_field_id, office_id) pair; repeat the call for each office the field should appear under. Once any custom_field_office rows exist for a field, it stops being visible to offices outside the list — so partners running multi-office or multi-region rollouts must add every office that should retain access. - [Bulk delete custom field options](https://harvestdocs.greenhouse.io/reference/delete_v3-custom-field-options-bulk.md): Asynchronously archive many options at once by id. Like the single-resource DELETE, this is a soft archive — rows are flagged `active: false`, historical selections are preserved, and archived options are still returned by the list endpoint unless `active=true` is passed. Per-item success or failure is reported through the bulk-status endpoint. - [Delete custom field option](https://harvestdocs.greenhouse.io/reference/delete_v3-custom-field-options-id.md): Archive a custom field option so it can no longer be selected on new records. Deletes are soft: the row stays in the database with `active: false`, historical selections on candidates, jobs, and offers are preserved, and the option still appears in list responses unless the caller passes `active=true`. To restore an archived option, PATCH it with the original `name`. - [List custom field options](https://harvestdocs.greenhouse.io/reference/get_v3-custom-field-options.md): Custom field options are the selectable values on a `single_select` or `multi_select` custom field — each row belongs to exactly one custom field via `custom_field_id`. Filter to a specific dictionary with `custom_field_ids` (preferred when the id is known) or `custom_field_key` (e.g. `school_name`, `degree`, `discipline`, `cost_center`). The V1 endpoints `/v1/schools`, `/v1/degrees`, and `/v1/disciplines` are all served here in V3 — pass the matching `custom_field_key`. Archived options remain in results by default; pass `active=true` to restrict to currently selectable options. - [Bulk update custom field options](https://harvestdocs.greenhouse.io/reference/patch_v3-custom-field-options-bulk.md): Asynchronously edit the label, sort order, or external id of many options in one call — most often used to reorder a dropdown after an upstream HRIS reshuffle or to rename options en masse. Each item must include `id`; the remaining fields are treated as a partial update. Per-item success or failure is reported through the bulk-status endpoint. - [Update custom field option](https://harvestdocs.greenhouse.io/reference/patch_v3-custom-field-options-id.md): Edit the display label, sort order, or external id of an existing custom field option. The parent `custom_field_id` cannot be moved through this endpoint — options stay attached to the field they were created under. To reactivate an archived option, PATCH it with the desired `name` (and the same `custom_field_id` it was archived from). - [Bulk create custom field options](https://harvestdocs.greenhouse.io/reference/post_v3-custom-field-options-bulk.md): Asynchronously add many options at once, typically for HRIS sync workflows that replace or extend a dropdown's option set in a single pass. Each item includes its own `custom_field_id`, so one batch can target multiple parent fields. A `bulk_action_uuid` is returned immediately. Per-item success or failure is reported through `GET /v3/bulk_requests/{bulk_action_uuid}`. - [Create custom field option](https://harvestdocs.greenhouse.io/reference/post_v3-custom-field-options.md): Add a new selectable value to a `single_select` or `multi_select` custom field. The parent field is identified by `custom_field_id` in the request body. If an archived option with the same name already exists on the field, this call returns 422 — reactivate that option with a PATCH (`active: true`) instead of creating a duplicate. - [Delete custom field](https://harvestdocs.greenhouse.io/reference/delete_v3-custom-fields-id.md): Permanently delete a custom field from your organization's dictionary, along with all stored values on parent records (jobs, offers, candidates, applications, etc.) and any associated `custom_field_options`. This action cannot be undone; to retire a field while preserving historical values, archive it via the update endpoint by setting it inactive in the UI instead. - [List custom fields](https://harvestdocs.greenhouse.io/reference/get_v3-custom-fields.md): Custom fields are the org-defined dictionary of structured data your organization layers onto core resources — jobs, offers, openings, candidates, applications, and users. Each row defines one field: its `field_type` selects the parent resource it attaches to, and its `value_type` selects the data type and editor (text, number, currency, single/multi-select, date, user, attachment, etc.). Replaces the V1 path-scoped endpoints `/v1/custom_fields/{field_type}` — filter by `field_type` as a query parameter instead. For select-type fields, options live on the sibling resource `/v3/custom_field_options`; office/department visibility lives on `/v3/custom_field_offices` and `/v3/custom_field_departments`. - [Update custom field](https://harvestdocs.greenhouse.io/reference/patch_v3-custom-fields-id.md): Edit the definition of an existing custom field. `field_type` and `value_type` are immutable — to change either, create a new field. As with create, the accepted properties vary by the field's existing `field_type`: job and opening fields expose approval and visibility toggles, offer fields expose `trigger_new_version`, user attributes are limited to `name`, `description`, and `required`. Manage option lists for select-type fields through `/v3/custom_field_options`, not this endpoint. - [Create custom field](https://harvestdocs.greenhouse.io/reference/post_v3-custom-fields.md): Add a new custom field to your organization's dictionary. `name`, `field_type`, and `value_type` are required. The request body shape varies by `field_type` — `job`, `offer`, `opening`, and `user_attribute` accept type-specific properties (e.g. `require_approval` for job/opening fields, `trigger_new_version` for offer fields). For `single_select` and `multi_select` fields, supply the initial option list inline via `custom_field_options`; after creation, manage options through `/v3/custom_field_options`. - [List default interviewers](https://harvestdocs.greenhouse.io/reference/get_v3-default-interviewers.md): Default interviewers are the users pre-selected as the interview panel for a specific stage on a job. When a candidate reaches that stage, these users are auto-populated as interviewers on a new interview; the scheduler can still pick different people, so this list reflects the default, not the final panel. Each row pairs one user with one interview kit (a kit represents one stage's setup on one job). Defaults configured in the UI as interviewer groups or hiring-team roles are not exposed here — only rows backed by an individual user are returned. - [List demographic answer options](https://harvestdocs.greenhouse.io/reference/get_v3-demographic-answer-options.md): Demographic answer options are the selectable choices on a `demographic_question`. Each option belongs to a single question; multi-select and single-select questions both draw their choices from this resource. Free-text input is modeled as an option with `free_form=true`, and the `I don't wish to answer` choice is identified by `decline_to_answer=true` rather than by matching on `name`. - [List demographic answers](https://harvestdocs.greenhouse.io/reference/get_v3-demographic-answers.md): Demographic answers are individual applicant submissions to the organization's voluntary demographic questions on a job post — distinct from the federally-mandated EEOC questionnaire, which has its own resource. Each row pairs an `application` with a `demographic_question` and the chosen `demographic_answer_option`; multi-select questions return one row per selected option, and rows backing a free-form `Other` choice carry the applicant's text in `free_form_text`. These responses are self-identification data and should be treated with the same sensitivity as EEOC responses. - [List demographic question sets](https://harvestdocs.greenhouse.io/reference/get_v3-demographic-question-sets.md): Demographic question sets are named groupings of `demographic_questions` an organization attaches to a job post or candidate survey to collect self-reported applicant demographic data (e.g. for DE&I reporting). A set is either custom (defined by the organization) or linked to a Greenhouse-supplied standard set; in both cases its child questions live under `/v3/demographic_questions?demographic_question_set_id={id}`. Inactive (soft-removed) and disabled sets are returned by default so historical applicant submissions stay readable — use `active` and `enabled` to narrow to live sets only. - [List demographic questions](https://harvestdocs.greenhouse.io/reference/get_v3-demographic-questions.md): Demographic questions are the voluntary self-identification prompts applicants see on job posts and candidate surveys (separate from the EEOC questionnaire, which carries its own legally-mandated wording). Each question belongs to a `demographic_question_set`, has a single- or multi-select `answer_type`, and pulls its choices from `demographic_answer_options`. The set returned here includes both organization-defined custom questions and Greenhouse-provided U.S. Standard Demographic Questions; standard ones are not editable. - [List departments](https://harvestdocs.greenhouse.io/reference/get_v3-departments.md): Departments are the organizational units jobs are assigned to (e.g. `Engineering`, `Marketing`). Each organization maintains its own department tree, with `parent_id` linking a department to its immediate parent and `null` marking top-level departments. Use this endpoint to discover department ids and `external_id` mappings before referencing them on jobs, candidate filters, or custom field scoping. - [Bulk update departments](https://harvestdocs.greenhouse.io/reference/patch_v3-departments-bulk.md): Asynchronously update many departments in a single request. Each item in `data` accepts the same fields as `PATCH /v3/departments/{id}` and must include the department's `id`. The request returns `202 Accepted` with a `bulk_action_uuid`; poll `/v3/bulk_requests/{bulk_action_uuid}` for status and per-record success/failure files. - [Update department](https://harvestdocs.greenhouse.io/reference/patch_v3-departments-id.md): Update an existing department's name, `external_id`, or position in the department tree. Use `parent_id` (or `external_parent_id`) to re-parent the department; both are optional on update and the existing parent is preserved when neither is supplied. - [Create department](https://harvestdocs.greenhouse.io/reference/post_v3-departments.md): Create a department in the caller's organization. Supply `parent_id` (or `external_parent_id`) to nest the new record under an existing department; omit both to create a top-level department. Set `external_id` to keep the new Greenhouse department mapped to the matching record in your HRIS or other external system. - [List EEOC](https://harvestdocs.greenhouse.io/reference/get_v3-eeoc.md): EEOC responses capture a candidate's voluntary self-identification of race, gender, veteran status, and disability status, collected via the federally-approved Equal Employment Opportunity Commission questionnaire. Each row belongs to a single application and is keyed by `application_id`; a candidate who applies to multiple jobs may have multiple responses. Categories are a fixed enum set by the regulator and cannot be customized — for org-defined demographic questions, use `/v3/demographic_questions` instead. Sensitive PII: unlike the in-app EEOC report (which only exposes aggregated, anonymized counts), this endpoint returns row-level responses tied to a specific candidate and application. Access is gated on the `harvest:eeoc:list` scope and partner permissions are typically restricted accordingly. - [List email templates](https://harvestdocs.greenhouse.io/reference/get_v3-email-templates.md): Email templates are reusable subject/body pairs your organization uses to communicate with candidates, prospects, and the hiring team. Each template is categorized by `email_type` (e.g. `candidate_rejection`, `interviewer_invite`, `extending_offer`), which determines where it appears in the UI and which merge tokens — like `{{CANDIDATE_FIRST_NAME}}` or `{{JOB_NAME}}` — are valid in its `subject` and body. Templates are either organization-wide (available to every user who can send that `email_type`) or personal to a single user (`user_id`). The body is returned as `html_body` for HTML notification types and `body` for plain-text types — exactly one of the two is populated for any given template. - [List focus candidate attributes](https://harvestdocs.greenhouse.io/reference/get_v3-focus-candidate-attributes.md): Focus candidate attributes are the subset of a job's `job_candidate_attributes` that an individual interview kit elevates as focus areas — the attributes Greenhouse highlights at the top of the interviewer's scorecard so they know which traits to prioritize for that interview. The set is per interview kit, so the same `job_candidate_attribute` can appear as a focus attribute on multiple kits within the same job. Each row carries only the foreign keys — the attribute's display name and `candidate_attribute_type` come from the parent `job_candidate_attribute`. Filter by `interview_kit_ids` to retrieve a single kit's focus attributes, or by `job_candidate_attribute_ids` to find every interview kit that focuses on a given attribute. Today this endpoint is site-admin-only. - [Delete future job permission](https://harvestdocs.greenhouse.io/reference/delete_v3-future-job-permissions-id.md): Revoke a single future job permission by id. Previously-created jobs that already granted the user a role via this permission are not affected; only future jobs stop matching. Deactivated users' future job permissions can also be deleted through this endpoint. - [List future job permissions](https://harvestdocs.greenhouse.io/reference/get_v3-future-job-permissions.md): Future job permissions grant a user a Job Admin role on jobs that don't exist yet — when a new job is created in the matching department and/or office, the permission automatically assigns the user that role on the job. Each row represents one user/role/scope combination; a user with multiple scoped permissions appears in multiple rows. When both `department_id` and `office_id` are `null`, the permission applies to every future job in the organization. Filter with `user_ids`, `role_ids`, `department_ids`, or `office_ids` to narrow the result set; use `external_department_id` or `external_office_id` to filter by partner-supplied scope identifiers without an extra id lookup. - [Create future job permission](https://harvestdocs.greenhouse.io/reference/post_v3-future-job-permissions.md): Grant a user a Job Admin role on future jobs matching an optional department and/or office scope. Pass `department_id` (or `external_department_id`) and/or `office_id` (or `external_office_id`) to restrict the scope; omit all four to grant the role on every future job in the organization. The `role_id` must reference a Job Admin organization role. Site admins already have access to every non-confidential job, so creating a future job permission for a site admin is a no-op and returns `204 No Content` instead of `201 Created`. - [List interview kits](https://harvestdocs.greenhouse.io/reference/get_v3-interview-kits.md): Interview kits are the per-job, per-slot evaluation packets interviewers see when conducting an interview — the instructions, exercises, scorecard questions, and focus attributes attached to one slot on one job's interview plan. Each kit belongs to a job and to a single `job_interview` slot; the `scorecard_questions` for that slot hang off the kit's `id`. Scope the list with `parent=job|job_interview` plus `ids` to pull the kits for one or more jobs or interview slots. Unlike the snapshot `summary` and `instructions` fields on the `job_interviews` endpoint, the `exercises` field here reflects the live Interview Prep content as edited on the job — use this endpoint when you need the current copy interviewers will actually see. - [List interviewer tags](https://harvestdocs.greenhouse.io/reference/get_v3-interviewer-tags.md): Interviewer tags are organization-defined labels assigned to interviewer users, such as "Bar Raiser," "Diversity Trained," or "Senior." They are surfaced as Interviewer Groups in the Greenhouse UI and used by schedulers to narrow the pool of interviewers when selecting one for a stage. A user can belong to multiple tags. To find which tags are assigned to a given user, request the `interviewer_tags` field on `GET /v3/users`. - [List interviewers](https://harvestdocs.greenhouse.io/reference/get_v3-interviewers.md): Interviewers are the panel members on actual scheduled interviews — each row pairs one interview with one user (or, for external attendees, one email address). When an interview is scheduled, the stage's default interviewers seed this panel, but the final attendee list can differ once the calendar event is built and edited. Each row carries its own `scorecard_id` (one placeholder scorecard per assigned interviewer) and a `response_status` reflecting the calendar RSVP. Filter to one parent with `parent=interview`, `parent=user`, or `parent=scorecard` plus `ids`. For the per-stage default panel, see `/v3/default_interviewers` instead. - [Delete interview](https://harvestdocs.greenhouse.io/reference/delete_v3-interviews-id.md): Cancel and delete a scheduled interview. Removes the Greenhouse interview record along with its interviewer assignments, scorecards-in-progress, and reminders. Only interviews in `scheduled` or `awaiting_feedback` are deletable; `complete` and other terminal-state interviews return 422. The matching event on the organizer's external calendar is not deleted from this endpoint — partners should remove the event on Google Calendar or Outlook in lockstep. - [List interviews](https://harvestdocs.greenhouse.io/reference/get_v3-interviews.md): Interviews are scheduled interview events on a candidate's application — each row pairs an application with a slot on the job's interview plan (the `job_interview`) and carries the start/end time, location, organizer, video conferencing link, and lifecycle status. Scope the list with `parent=application|job|job_interview|organizer` plus `ids` to pull interviews for one or more candidates, jobs, interview slots, or scheduling coordinators. Use the `starts_at` / `ends_at` filters for time-bounded interviews; use `all_day_start_on` / `all_day_end_on` for all-day events (e.g. take-home tests). Lookup by external calendar event id is supported via `external_event_id`. - [Update interview](https://harvestdocs.greenhouse.io/reference/patch_v3-interviews-id.md): Patch a scheduled interview's time, location, video conferencing link, external calendar event id, or interviewer panel. Reassign the panel by passing a full `interviewers` array (each entry must include `response_status` and identify the interviewer by `user_id`, `email`, or `employee_id`); the existing list is replaced wholesale. This endpoint updates the Greenhouse interview record only — partners scheduling through Google Calendar or Outlook should make the matching edit on the calendar event and let the calendar integration sync, rather than calling this endpoint in parallel. - [Create interview](https://harvestdocs.greenhouse.io/reference/post_v3-interviews.md): Schedule an interview against a candidate's application at a specific slot on the job's interview plan. `application_id`, `job_interview_id` (the interview-plan slot), `starts_at`, `ends_at`, and `external_event_id` (the id of the matching event on the organizer's external calendar) are required. Provide the panel via `interviewers`, where each entry must include `response_status` and identify the interviewer by `user_id`, `email`, or `employee_id`. `location` and `video_conferencing_url` are optional metadata copied onto the Greenhouse record; this endpoint records an already-scheduled calendar event rather than creating one on an external calendar. - [List job board custom locations](https://harvestdocs.greenhouse.io/reference/get_v3-job-board-custom-locations.md): Job board custom locations are the curated list of location strings a site admin maintains for posting jobs to a given job board. Each row belongs to exactly one `greenhouse_job_board` and backs the `custom_list` mode of `/v3/job_post_locations` — when a post references a custom location via `custom_location_id`, its displayable text is resolved from the matching row's `value`. Boards configured to use organization offices or free-text strings do not produce rows here; filter by `greenhouse_job_board_ids` to scope to a specific board. - [List job boards](https://harvestdocs.greenhouse.io/reference/get_v3-job-boards.md): A job board is a destination an organization publishes job posts to — either the organization's single internal board (visible only to signed-in employees) or one of its external boards (public careers site, embedded iFrame, or syndicated integration). Each `job_post` belongs to exactly one board, and board-level fields like `introduction`, `conclusion`, and `company_name` are applied to every post on the board. Only boards whose `status` is `live` serve public traffic at `https://job-boards.greenhouse.io/{url_token}`. - [List job candidate attributes](https://harvestdocs.greenhouse.io/reference/get_v3-job-candidate-attributes.md): Job candidate attributes are the per-job instances of a job's `candidate_attribute_types` — one row for each evaluable trait (e.g. `JavaScript`, `Leadership`) configured on a specific job. This is the canonical list of "what we're rating candidates on" for a given job and is the entry point most AI-matching partners read to score candidate fit. Each row carries the on-job display `name`, `active` flag, and `sort_order`, and points at its parent `candidate_attribute_type_id`; downstream, `focus_candidate_attributes` mark which of these are emphasized on a given interview kit and `scorecard_candidate_attributes` / `scorecard_question_candidate_attributes` carry the interviewer's ratings against them. Filter by `job_ids` to scope to one job or by `candidate_attribute_type_ids` to find every job using a given attribute type. Today this endpoint is site-admin-only. - [Delete job hiring manager](https://harvestdocs.greenhouse.io/reference/delete_v3-job-hiring-managers-id.md): Unassign a hiring manager from a job by deleting the join row. The `{id}` is the `id` of the `job_hiring_managers` row, not the `user_id` or `job_id`. The underlying user is not affected — only their hiring-manager assignment on this job is removed. - [List job hiring managers](https://harvestdocs.greenhouse.io/reference/get_v3-job-hiring-managers.md): Job hiring managers are users designated as hiring managers on a job — typically the subject-matter expert for the role who reviews candidates in the Hiring Manager Review stage and receives notifications about new applicants. Each row pairs one user with one job; a job can have multiple hiring managers, and the same user can hold the role on multiple jobs. Filter to one parent with `parent=job` or `parent=user` plus `ids`. - [Create job hiring manager](https://harvestdocs.greenhouse.io/reference/post_v3-job-hiring-managers.md): Assign a user as a hiring manager on a job. The user must already exist in your organization and have permissions on the job; assigning a hiring manager is the V3 replacement for the V1 `PUT /jobs/{id}/hiring_team` flow for the hiring-manager role. To remove a hiring manager, call `DELETE /v3/job_hiring_managers/{id}` with the row id returned here. - [List job interview stages](https://harvestdocs.greenhouse.io/reference/get_v3-job-interview-stages.md): Interview stages are the steps of a job's interview plan — for example `Application Review`, `Phone Screen`, `Onsite`, and `Offer`. Each stage belongs to a job and is referenced by `job_interviews` (the slots within the stage) and by `application_stages` (the per-application history of which stages a candidate has occupied). Every plan starts with `Application Review` (`sort_order: 0`) and ends with `Offer`; the stages in between can be picked from the Greenhouse stage library or created custom per job, so names and counts vary across jobs in the same organization. Scope the list with `parent=job` plus `ids` to pull the plan for one or more jobs; inactive stages are included by default and can be filtered out with `active=true`. - [List job interviews](https://harvestdocs.greenhouse.io/reference/get_v3-job-interviews.md): Job interviews are the interview slots configured on a job's interview plan — the template definitions that say, for example, "this job's Onsite stage has a 30-minute recruiter chat, a 45-minute hiring manager interview, and a take-home test." Each slot belongs to a `job_interview_stage` on a specific job and carries the default name, duration, scheduling type, and scorecard requirement. When a candidate reaches the stage, individual `interviews` are spun up from these slots and scheduled against the candidate's application — the `id` returned here is the `job_interview_id` you pass to the Create Interview endpoint. Scope the list with `parent=job|job_interview_stage` plus `ids` to pull the slots for one or more jobs or stages. `summary` and `instructions` reflect the slot's defaults at the time it was added to the job and do not stay in sync with later edits made to the interview's Interview Prep — use the Interview Kits endpoint for the live values. - [Delete job note](https://harvestdocs.greenhouse.io/reference/delete_v3-job-notes-id.md): Permanently delete a job note. The note is removed from the job's notes list and the deletion cannot be reversed. - [List job notes](https://harvestdocs.greenhouse.io/reference/get_v3-job-notes.md): Job notes are free-form, organization-internal notes attached to a job (the requisition). They capture hiring-team context about the role itself and are distinct from candidate notes, which are attached to a candidate or application. Each note has a `visibility` that controls whether it is readable by Job Admins on the job or further restricted to users with the "view and create private job notes" permission. - [Update job note](https://harvestdocs.greenhouse.io/reference/patch_v3-job-notes-id.md): Update an existing job note. Any subset of `body`, `visibility`, `job_id`, or `user_id` may be supplied; fields that are omitted are left unchanged. Changing `visibility` immediately tightens or loosens who can read the note. - [Create job note](https://harvestdocs.greenhouse.io/reference/post_v3-job-notes.md): Create a free-form note attached to a job. The note is anchored to the job referenced by `job_id` and authored on behalf of `user_id`; the resulting note is visible according to its `visibility` (`admin_only_visible` or `privately_visible`). - [Delete job owner](https://harvestdocs.greenhouse.io/reference/delete_v3-job-owners-id.md): Remove a user from the hiring team in one role by deleting the join row. The `{id}` is the `id` of the `job_owners` row, not the `user_id` or `job_id`. Only the user's assignment in this specific role is removed — the underlying user and any other roles they hold on this or other jobs are untouched. To remove a hiring manager, use `DELETE /v3/job_hiring_managers/{id}` instead. - [List job owners](https://harvestdocs.greenhouse.io/reference/get_v3-job-owners.md): Job owners are the recruiters, sourcers, and coordinators on a job's hiring team — the users who own sourcing, recruiting, and scheduling work for the role. Each row pairs one user with one job in one role; a user can hold multiple roles on the same job, and a job can have multiple users in each role. Filter to one parent with `parent=job` or `parent=user` plus `ids`, or narrow to a single role with `type`. Hiring managers are exposed on the separate `/v3/job_hiring_managers` endpoint. - [Create job owner](https://harvestdocs.greenhouse.io/reference/post_v3-job-owners.md): Add a user to a job's hiring team as a `recruiter`, `sourcer`, or `coordinator`. The user must already exist in your organization and have permission to edit the job. For `recruiter` and `coordinator`, pass `candidate_responsibility` to make this user the responsible owner for `active`, `inactive`, `future`, or `all` candidates on the job — omitting it leaves new applications without a responsible recruiter or coordinator. This is the V3 replacement for the V1 `POST /v1/jobs/{id}/hiring_team` flow for these three roles; hiring managers are assigned via `POST /v3/job_hiring_managers`. To remove a user from the hiring team, call `DELETE /v3/job_owners/{id}` with the row id returned here. - [Delete job post location](https://harvestdocs.greenhouse.io/reference/delete_v3-job-post-locations-id.md): Detach a single location from a job post. The `{id}` here is the `job_post_locations` row id (returned by list/create), not the `job_post_id`, `office_id`, or `custom_location_id`; resolve it via `GET /v3/job_post_locations?parent=job_post&ids=` when you only have the post. The referenced `office` and `job_board_custom_locations` rows are unaffected — this only removes the attachment from the post. - [List job post locations](https://harvestdocs.greenhouse.io/reference/get_v3-job-post-locations.md): Job post locations are the join rows that attach one or more locations to a `job_post` — a multi-location posting (e.g. `San Francisco`, `Remote (US)`, `New York` on a single role) has one row per location. `GET /v3/job_posts` does not return locations inline; pair this endpoint with it on `job_post_id` to assemble the candidate-facing location list. Filter with `parent=job_post&ids=` to fetch every location on a specific post, or with `parent=office` / `parent=custom_location` to find every post in a given location. - [Create job post location](https://harvestdocs.greenhouse.io/reference/post_v3-job-post-locations.md): Attach a location to an existing `job_post`. The supplied `type` must match the parent job board's location configuration — boards set to `office` or `custom_list` reject `free_text` values, and a `custom_list` value must reference a `job_board_custom_locations` row on the same board as the post. Issue one POST per location to build out a multi-location post; there is no batch create. To replace an existing location, delete the row via `DELETE /v3/job_post_locations/{id}` and post the new one. - [List job post searchable locations](https://harvestdocs.greenhouse.io/reference/get_v3-job-post-searchable-locations.md): Searchable locations are the individual geographic locations attached to a job post — one row per location, each with a formatted display string plus its component city, region (state/province), postal code, county, country, and latitude/longitude. A single job post can have many searchable locations. Each location's `id` is the searchable-location identifier used by downstream job boards: for example, Indeed composes its multi-location job identifier as `{job_post_id}_{id}`, so this endpoint is the canonical source for mapping those identifiers back to a job post and its location. Filter with `job_post_ids` to retrieve the locations for specific job posts. Results are scoped to the authenticated organization and to the locations the API user is permitted to access. - [List job posts](https://harvestdocs.greenhouse.io/reference/get_v3-job-posts.md): Job posts are the candidate-facing listings of a job. A single job can have multiple posts — typically one per locale, geography, or audience — each published to either an external `job_board` (a public careers site or syndicated board like LinkedIn) or the organization's internal job board. Posts carry their own public title, HTML description, application form questions, and `live` state independent of the parent job. - [Update job post](https://harvestdocs.greenhouse.io/reference/patch_v3-job-posts-id.md): Edit a job post in place — change its public title, replace its HTML body, or transition its publication status between `draft` and `live`. Content updates route to `internal_content` for internal posts and to `content` for external posts automatically. Transitioning to `live` only publishes the post on its job board if the board itself is also live; otherwise the post is marked live but its `public_url` will not be reachable until the board is enabled. - [Create job post](https://harvestdocs.greenhouse.io/reference/post_v3-job-posts.md): Create a new job post by duplicating an existing one. The new post is attached to the same parent job as the template (`template_job_post_id`) and published to the supplied `job_board_id`. Use this to spin up additional language, geography, or board variants of a job's listing without re-entering the content, application questions, or settings. To create the first post on a job, post a template from another job and adjust the resulting post; this endpoint does not create a post from scratch. - [List jobs](https://harvestdocs.greenhouse.io/reference/get_v3-jobs.md): Jobs are the open requisitions and hiring plans your organization is recruiting against. A job carries the role's department, offices, hiring team, interview plan, and custom fields, and is the parent of the openings (headcount slots), job posts (public listings), and applications attached to it. In V3 these related collections live on their own resource endpoints — `/v3/openings`, `/v3/job_posts`, `/v3/applications`, `/v3/job_hiring_managers`, etc. — rather than inlined on the job. Filter by `status` (`open`, `closed`, `draft`), department, office, requisition id, or custom field selection; the response is scoped to jobs the caller's permissions can see. - [Update job](https://harvestdocs.greenhouse.io/reference/patch_v3-jobs-id.md): Patch an existing job's editable fields. Only the keys included in the request body are modified; omitted keys are left untouched. `office_ids` / `external_office_ids` and `custom_fields` replace their existing collections wholesale — send the full desired list, not a delta. Department and office can be set either by Greenhouse id or by partner `external_id`; the two forms are mutually exclusive. To open, close, or re-open a job, modify its openings through `/v3/openings` — the job's `status` and `opened_at`/`closed_at` follow automatically. - [Bulk create jobs](https://harvestdocs.greenhouse.io/reference/post_v3-jobs-bulk.md): Asynchronously create many jobs in a single call, typically for HRIS sync workflows that open a batch of requisitions at once. Each item follows the same shape as `POST /v3/jobs`, with `template_job_id` and `number_of_openings` required, and is processed independently. A `bulk_action_uuid` is returned immediately. Per-item success or failure is reported through `GET /v3/bulk_requests/{bulk_action_uuid}`. - [Create job](https://harvestdocs.greenhouse.io/reference/post_v3-jobs.md): Create a new job from an existing template. `template_job_id` and `number_of_openings` are required; the template supplies the interview plan, scorecards, hiring team, and approval workflow, since Greenhouse Recruiting remains the source of truth for those configurations. One opening is created for each requested slot, optionally tagged with a partner `opening_ids` entry. Department and offices can be set either by Greenhouse id (`department_id`, `office_ids`) or by partner `external_id` (`external_department_id`, `external_office_ids`) — the id and external-id forms are mutually exclusive. The legacy `confidential` flag cannot be set through this endpoint. - [List notes](https://harvestdocs.greenhouse.io/reference/get_v3-notes.md): Notes are free-form entries on a candidate's profile — candidate notes, logged emails, system activity, interview feedback, and other entries that appear in the candidate activity feed. Each note is anchored to a candidate and optionally to a specific application. This endpoint returns every note type, including read-only entries (interview notes, scorecard-linked feedback, LinkedIn messages, touchpoints) that cannot be created through `POST /v3/notes`. For interview feedback and scorecard takeaways, use the Scorecards endpoints instead — they expose the structured form data, while this endpoint only exposes the underlying note body. - [Create note](https://harvestdocs.greenhouse.io/reference/post_v3-notes.md): Create a candidate note, log an email, or record an activity-feed entry on a candidate. `note_type` selects which: `NOTE` posts to the Notes tab, `EMAIL` logs an email into the activity feed (and requires the `email_*` fields), and `ACTIVITY` writes a free-form activity-feed entry. Other note types (interview, feedback, touchpoint, LinkedIn, etc.) are produced by Greenhouse features and cannot be created through this endpoint. The note is always attached to `candidate_id`; pass `application_id` as well to anchor it to a specific application — that application must belong to the same candidate. - [List offers](https://harvestdocs.greenhouse.io/reference/get_v3-offers.md): Offers are the formal job offers extended to a candidate's application. Each offer belongs to one application and carries a `status` (`Created`, `Accepted`, `Rejected`, or `Deprecated`), a proposed start date, an optional `opening_id`, and a `custom_fields` map that holds compensation components (base pay, equity, bonus, etc.) alongside any other offer custom fields configured on the hiring plan. Greenhouse versions offers — changing the start date, opening, or a version-triggering custom field creates a new offer row with an incremented `version` for the same application; pass `current_only=true` to filter the list down to the latest version per application. Filter by parent with `application_ids`, `job_ids`, `candidate_ids`, or `opening_ids`; combine `status=Accepted` with the `resolved_at` filter as a hire-date filter. Offer approvals flow through a separate `approval_flow` — see `/v3/approval_flows` for status. - [Update offer](https://harvestdocs.greenhouse.io/reference/patch_v3-offers-id.md): Patch fields on an existing offer. Only the keys included in the request body are modified; omitted keys are left untouched. Updates to `starts_on`, the offer's `opening_id`, or version-triggering custom fields create a new offer `version` for the same application rather than mutating the prior row — fetch the updated offer with `current_only=true` to find the new current version. The date-typed `created_at`, `sent_on`, and `resolved_at` fields are intended for backfilling offers managed outside Greenhouse; `resolved_at` updates are normalized to noon UTC on the supplied date. `custom_fields` entries set values for the offer's offer custom fields (including compensation components); only fields configured on the application's hiring plan apply. - [Create offer](https://harvestdocs.greenhouse.io/reference/post_v3-offers.md): Create a new offer on an existing application. `application_id` is required; `starts_on` and `custom_fields` (compensation components plus any offer custom fields configured on the hiring plan) are optional. The new offer is created with `status=Created` at `version=1`. If the application already has an offer, the submission is applied to the same offer chain rather than creating a competing record: a new version is created — and the prior version marked `Deprecated` — only when a version-triggering field changes, namely `starts_on` (when your organization enables offer versioning on start-date changes) or a compensation/offer custom field configured to trigger a new version; otherwise the current offer is updated in place. Approval flows configured for the hiring plan are attached automatically — partners must drive the approval through `/v3/approval_flows` before the offer can be sent to the candidate. - [List offices](https://harvestdocs.greenhouse.io/reference/get_v3-offices.md): Offices are the organization's recruiting locations (e.g. `San Francisco`, `New York`, `Remote (US)`) and the foundational scoping unit for jobs, candidates, custom-field visibility, and pay-range display. Each organization defines its own office set, optionally organized as a hierarchy via `parent_id`. Use this endpoint to enumerate the office tree for filtering, lookup, or downstream resource scoping. - [Bulk update offices](https://harvestdocs.greenhouse.io/reference/patch_v3-offices-bulk.md): Update up to the bulk-endpoint cap of offices in a single request. Each item in `data` must include the `id` of the target office plus the fields to change (same body shape as `PATCH /v3/offices/{id}`). Each row is processed independently and the response reports per-row success or failure; rows that fail validation do not block the others. Use for HRIS-driven syncs that touch many offices at once. - [Update office](https://harvestdocs.greenhouse.io/reference/patch_v3-offices-id.md): Update an existing office. Any subset of `name`, `location`, `external_id`, `parent_id` (or `external_parent_id`), and `primary_in_house_contact_user_id` may be supplied; fields that are omitted are left unchanged. Re-parenting via `parent_id` and `external_parent_id` is mutually exclusive — pass one or the other, never both. - [Create office](https://harvestdocs.greenhouse.io/reference/post_v3-offices.md): Create a new office for the organization. Provide a `name` and, optionally, a `location`, an `external_id`, a `primary_in_house_contact_user_id`, and a parent reference (either `parent_id` or `external_parent_id`, not both). Tiered offices require the `tiered_offices_and_departments` product flag; `external_id` requires the `org_structure_external_id` product flag. - [Bulk delete openings](https://harvestdocs.greenhouse.io/reference/delete_v3-openings-bulk.md): Asynchronously remove many openings in a single call. Each item is an opening ID and is processed independently. The same constraints as `DELETE /v3/openings/{id}` apply per item, so only closed openings with no attached offer and no filling application are deleted. Protected openings fail individually and are reported in the results from `GET /v3/bulk_requests/{bulk_action_uuid}`. A `bulk_action_uuid` is returned immediately. - [Delete opening](https://harvestdocs.greenhouse.io/reference/delete_v3-openings-id.md): Permanently remove an opening from its job. Only closed openings with no attached offer and no filling application can be deleted — openings that are still `open`, or that were closed as a hire (`application_id` set), are protected and must remain on the job for record-keeping. To close an opening without removing it, use `PATCH /v3/openings/{id}` with `status: "closed"` instead. - [List openings](https://harvestdocs.greenhouse.io/reference/get_v3-openings.md): Openings are the individual headcount slots beneath a job — one opening per seat you intend to hire for. Each opening is filled when a candidate is hired against it (`status` becomes `closed` and `application_id` is populated) or closed without a hire (with a `close_reason_id`); closing the last open opening on a job automatically closes the job. Filter by parent (`job_id`, `application_id`, `close_reason_id`), by partner-supplied `opening_id`, by `open`/`closed` state, or by an `opened_at` / `closed_at` window for incremental HRIS-style syncs. - [Bulk update openings](https://harvestdocs.greenhouse.io/reference/patch_v3-openings-bulk.md): Asynchronously patch many openings in a single call, commonly for HRIS integrations that close batches of headcount with `status: "closed"` and `close_reason_id`, or reconcile partner `opening_id` values after a sync. Each item follows the same shape as `PATCH /v3/openings/{id}` with an additional `id` key identifying the opening, and is processed independently. A `bulk_action_uuid` is returned immediately. Per-item success or failure is reported through `GET /v3/bulk_requests/{bulk_action_uuid}`. - [Update opening](https://harvestdocs.greenhouse.io/reference/patch_v3-openings-id.md): Patch an existing opening's editable fields, or change its status. Only the keys included in the request body are modified; omitted keys are left unchanged. Pass `status: "closed"` to close an open opening. Include `close_reason_id` when closing if your organization requires one. Closing the last open opening on a job automatically closes the job. Pass `status: "open"` to reopen a closed opening that has not been filled; reopening a filled opening returns 422. `custom_fields` replaces the opening's custom-field values wholesale, so send the full desired list, not a delta. - [Bulk create openings](https://harvestdocs.greenhouse.io/reference/post_v3-openings-bulk.md): Asynchronously add many openings across one or more jobs in a single call, typically for HRIS sync workflows that open or extend headcount on a batch of requisitions. Each item follows the same shape as `POST /v3/openings`, with `job_id` required, and is processed independently. A `bulk_action_uuid` is returned immediately. Per-item success or failure is reported through `GET /v3/bulk_requests/{bulk_action_uuid}`. The 100-open-openings-per-job limit still applies and is evaluated per item. - [Create opening](https://harvestdocs.greenhouse.io/reference/post_v3-openings.md): Add a new headcount slot to an existing job. `job_id` is required; `opening_id` is an optional partner-supplied external identifier (e.g. an HRIS or ATS position id) and `custom_fields` set values on the organization's opening custom fields. Greenhouse enforces an internal limit of 100 open openings per job — requests that would exceed it are rejected. To create a batch of openings alongside a new job, use `POST /v3/jobs` with `number_of_openings` instead. - [List pay input ranges](https://harvestdocs.greenhouse.io/reference/get_v3-pay-input-ranges.md): Pay input ranges are the per-job-post minimum and maximum values for a pay component (e.g. base salary, bonus) referenced by a pay transparency rule. Each range belongs to one `pay_input` and one `job_post`; the same job can publish different ranges on different posts. Greenhouse renders these ranges on public job posts to satisfy pay transparency laws (e.g. NY, CA, CO). `min_cents` and `max_cents` are expressed in the smallest unit of `currency_type` and are `0` when the range has not yet been filled in on the job post. - [List pay inputs](https://harvestdocs.greenhouse.io/reference/get_v3-pay-inputs.md): Pay inputs are the individual compensation components (e.g. `Base Salary`, `Sign-on Bonus`, `Equity`) that make up a Greenhouse pay transparency rule. Site Admins configure them under Configure > Privacy & Compliance, and each pay input belongs to a pay transparency rule that gets attached to a job post; the dollar amounts themselves live on the sibling `/v3/pay_input_ranges` resource. Pay inputs may optionally sync from a currency-range custom job field via `linked_custom_field_id` — when present, the pay range is sourced from that field and is locked on the job post if `locked` is `true`. - [List prospect details](https://harvestdocs.greenhouse.io/reference/get_v3-prospect-details.md): A prospect detail is the per-prospect record that captures where a candidate sits in the CRM: which prospect pool and stage they currently occupy, who owns them, and the department/office they are being considered for. Each prospect detail is attached to exactly one prospect application (an application that has not yet been moved onto a job); together with `/v3/prospect_pools` and `/v3/prospect_pool_stages`, these rows let an integration reconstruct the full state of a customer's CRM pipeline. `department_id` and `office_id` are derived from the application's prospective department record, not from the candidate or job, so they may differ from the offices and departments returned by other endpoints for the same application. - [List prospect pool stages](https://harvestdocs.greenhouse.io/reference/get_v3-prospect-pool-stages.md): Prospect pool stages are the smaller buckets inside a prospect pool that recruiters use to track where each passive prospect sits in their nurture process — for example `Not Reviewed`, `In Discussion`, or `Keep Warm - Senior`. Each stage belongs to a single prospect pool; a prospect's `current_prospect_pool_stage_id` points at the row they currently occupy. Stage names and counts are fully customer-defined per pool (there is no Greenhouse-managed default set), so the same name can appear in multiple pools but is unique within a pool. Scope the list with `parent=prospect_pool` plus `ids` to pull the stages for one or more specific pools. - [List prospect pools](https://harvestdocs.greenhouse.io/reference/get_v3-prospect-pools.md): A prospect pool is an organization-defined collection of prospects (candidates not yet attached to a specific job), typically used to manage talent communities and sourcing pipelines. Each pool has its own ordered set of stages (see `/v3/prospect_pools/{prospect_pool_id}/stages`) that prospects move through, distinct from a job's interview plan. Pools may be restricted to specific departments, offices, or jobs (hiring plans) via `department_ids`, `office_ids`, and `job_ids`; when all three are empty, the pool is available organization-wide. - [List referrers](https://harvestdocs.greenhouse.io/reference/get_v3-referrers.md): Referrers are the people credited with bringing a candidate into the pipeline — typically employees making referrals, but also agency recruiters, LinkedIn recruiters, or any other party captured under "Who Gets Credit" on a candidate's application. Each row is one referrer in the organization; resolve a referrer for an application by joining `applications.referrer_id` to this resource's `id`. A referrer is distinct from a Greenhouse user and from a source: `user_id` may link a referrer to a user when one exists but is often `null`, and the `Referral` source on an application tells you the channel while the referrer tells you the specific person credited. Filter to a single user's referrer records with `user_ids`. This endpoint is read-only; referrers are created and edited through the Greenhouse UI, not the Harvest API. - [List rejection details](https://harvestdocs.greenhouse.io/reference/get_v3-rejection-details.md): Rejection details are the per-application rejection records — one row per rejected application, capturing who rejected it, when, why (the rejection reason), the linked rejection note, and any answers to the organization's rejection question custom fields. A rejection detail exists only after an application has been rejected; non-rejected applications are not represented here. Filter with `application_ids` to pull rejection details for specific applications, or with `rejection_reason_ids` to slice by reason (useful for auto-rejection workflow reporting, e.g. spam or time-bound rejections). To patch a rejection's reason or custom field answers, fetch the rejection detail id from this endpoint and pass it to `PATCH /v3/rejection_details/{id}` — the path id is the rejection detail id, not the application id. - [Update rejection detail](https://harvestdocs.greenhouse.io/reference/patch_v3-rejection-details-id.md): Patch the rejection reason or rejection question custom field answers on a rejected application without changing its `rejected_at` timestamp. The `{id}` path parameter is the rejection detail record id, not the application id — fetch it from `GET /v3/rejection_details?application_ids={application_id}` first. The application must already be rejected; this endpoint cannot reject an application that is still in process. Only the keys included in the request body are modified; `custom_fields` replaces the listed rejection question values wholesale. - [Retrieve rejection reason](https://harvestdocs.greenhouse.io/reference/get_v3-rejection-reasons-id.md): Retrieve a single rejection reason by id. Use this to resolve the human-readable `name` and the categorization `type` (`We rejected them`, `They rejected us`, `None specified`, or `Security concern`) for a `rejection_reason_id` referenced from a `rejection_details` record on a rejected application. The reason must belong to the calling organization, or — for Greenhouse's built-in default reasons — be returned by the matching list endpoint with `include_defaults=true`. - [List rejection reasons](https://harvestdocs.greenhouse.io/reference/get_v3-rejection-reasons.md): Rejection reasons are the organization-defined dictionary of outcomes recorded when an application is rejected (e.g. `Not a cultural fit`, `Lacking skill(s)/qualification(s)`, `Wasn't interested`, `Didn't like offer`, `Spam`). Each rejected `application` references one of these through its `rejection_details.rejection_reason`; this endpoint is the source of truth for the picklist itself. Reasons are grouped under a `type` of `We rejected them`, `They rejected us`, `None specified`, or `Security concern` — use the type to distinguish the organization declining the candidate from the candidate withdrawing, and to identify trust/fraud outcomes in reporting. Customized per organization under Configure > Custom Options > Rejection Reasons, so the available set varies between Greenhouse accounts; pass `include_defaults=true` to also return the standard reasons that ship with every account. Reasons of type `Security concern` are only returned when the `enable_reject_as_security_concern` product flag is on. Distinct from `rejection_details`, which carries the per-application rejection instance attached to a rejected application, and from `close_reasons`, which apply to openings rather than applications. - [List scorecard candidate attributes](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-candidate-attributes.md): Scorecard candidate attributes are the per-scorecard ratings an interviewer captured on each focus attribute — what they thought of this candidate on each attribute on this scorecard. Each row pairs one `scorecard` with one `job_candidate_attribute` (the per-job attribute being rated) and carries the rating in `candidate_attribute_rating` plus an optional free-text `note`. Filter by `scorecard_ids` to pull every attribute rating on a given scorecard, or by `job_candidate_attribute_ids` to see how interviewers rated the same attribute across scorecards (the read pattern used by talent-matching and partner interview-intelligence integrations). Sibling to `/v3/scorecard_question_candidate_attributes`, which maps questions to attributes on the interview kit rather than capturing interviewer ratings. - [List scorecard question answer options](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-question-answer-options.md): Scorecard question answer options are the join rows between a scorecard question answer and the option(s) selected for it — one row per (`scorecard_question_answer_id`, `scorecard_question_option_id`) pair. A `multi_select` answer can have many rows here; a `single_select` answer has at most one. Filter with `scorecard_question_answer_ids` to list every option selected for a set of answers, or `scorecard_question_option_ids` to find every answer that picked a given option. The option labels and the answer's free-text content live on `/v3/scorecard_question_options` and `/v3/scorecard_question_answers`; this endpoint only exposes the foreign keys. - [List scorecard question answers](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-question-answers.md): A scorecard question answer is one interviewer's response to a single question on a scorecard. Each row pairs a `scorecard` with a `scorecard_question` and carries the response in `answer` (for `text` questions) or `boolean_value` (for `yes_no` questions); responses to `single_select` and `multi_select` questions are stored as `scorecard_question_answer_options` linked to this row. Filter by `scorecard_ids` to pull every answer on a given scorecard, or by `scorecard_question_ids` to compare how interviewers responded to the same question across scorecards. - [List scorecard question candidate attributes](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-question-candidate-attributes.md): Scorecard question candidate attributes are the join that tells an interviewer which focus attributes a given scorecard question is asking them to assess. Each row pairs one `scorecard_question` with one `focus_candidate_attribute` — there is no rating or note on the join itself; the actual interviewer answer lives on `scorecard_candidate_attributes`. Despite the resource name, the foreign key points at a `focus_candidate_attribute` (per interview kit), not directly at a `job_candidate_attribute` or `candidate_attribute_type`. Filter by `scorecard_question_ids` to find every focus attribute a given question covers, or by `focus_candidate_attribute_ids` to find every scorecard question that evaluates a given focus attribute. Today this endpoint is site-admin-only. - [List scorecard question options](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-question-options.md): Scorecard question options are the multiple-choice values shown to interviewers for `single_select` and `multi_select` `scorecard_questions`. Each option belongs to a single parent question; the interviewer's selection is recorded on a `scorecard_question_answer` through the `scorecard_question_answer_options` join. Filter to a single question with `scorecard_question_id` and to live options with `active=true`. - [List scorecard questions](https://harvestdocs.greenhouse.io/reference/get_v3-scorecard-questions.md): Scorecard questions are the prompts configured on an `interview_kit` that interviewers answer when submitting a scorecard. Each question has a `question` body and an `answer_type` (`text`, `yes_no`, `single_select`, `multi_select`, or `instruction`); `single_select` and `multi_select` questions reference their choices through `/v3/scorecard_question_options`. Interviewer responses are returned separately as `scorecard_question_answers` on a candidate's scorecards. Filter to a single kit with `interview_kit_id` and to live questions with `active=true`. - [List scorecards](https://harvestdocs.greenhouse.io/reference/get_v3-scorecards.md): Scorecards are the per-interview evaluations that interviewers fill out — overall recommendation, key takeaways, private and public notes, and ratings on the interview kit's focus attributes. Each interviewer on an interview receives their own scorecard. Scorecards start in `draft` status and move to `complete` when submitted (at which point `submitted_at` is stamped); filter on `status` to separate in-progress scorecards from finalized ones. - [List sources](https://harvestdocs.greenhouse.io/reference/get_v3-sources.md): Sources are the organization-defined dictionary of channels through which candidates enter the pipeline — job boards (e.g. `LinkedIn`, `Indeed`), agencies, referrals, internal applicants, prospecting tools, events, and other ways an application is attributed. Each application references a single source via `source_id`; resolve the human-readable label and its broader category (sourcing strategy) here. The response is a mix of Greenhouse's built-in global sources and any custom sources the organization has configured under Configure > Custom Options > Sources, so the available set varies between accounts. Distinct from `tracking_links`, which are URLs that auto-tag a source on incoming applications. - [List tracking links](https://harvestdocs.greenhouse.io/reference/get_v3-tracking-links.md): Tracking links are unique short URLs (e.g. `https://grnh.se/`) that an organization shares to attribute candidates to a `source` — campaign URLs, referral links, employee outreach, social posts, and third-party board placements. When a candidate applies through a tracking link, the application inherits the link's `source_id` and any related attribution (referrer, related post). Each link belongs to exactly one organization and is scoped to a job, job board, or job post. - [List user emails](https://harvestdocs.greenhouse.io/reference/get_v3-user-emails.md): User emails are the email addresses attached to a Greenhouse user. A user can hold multiple addresses — typically one work email plus aliases or historical addresses — but only one is the primary, which Greenhouse uses for sign-in and notifications and is exposed as `primary_email` on the `/v3/users` resource. Use this endpoint to resolve a list of addresses back to users (e.g. matching candidate-attributed emails to interviewer calendars), or to audit which secondary aliases are verified. The primary email itself cannot be switched through Harvest; use `POST /v3/user_emails` to add secondaries. - [Create user email](https://harvestdocs.greenhouse.io/reference/post_v3-user-emails.md): Attach an additional email address to a Greenhouse user — the V3 replacement for V1 `POST /users/{id}/email_addresses`. This only adds secondary addresses; it cannot change the user's primary email or replace an existing address. Emails are globally unique across users, so attempting to attach an address that already belongs to anyone returns 409. Re-posting an address that already exists on the target user with `send_verification=true` while it is still unverified resends the verification email and returns 200 instead of 201. - [Delete user job permission](https://harvestdocs.greenhouse.io/reference/delete_v3-user-job-permissions-id.md): Revoke a single user job permission by id, removing that user's Job Admin role on the job. Does not affect site admin access (site admins are not represented in this resource) and does not remove any `future_job_permission` that may regrant access if the job's office/department scope matches. - [List user job permissions](https://harvestdocs.greenhouse.io/reference/get_v3-user-job-permissions.md): User job permissions are the per-user, per-job access grants that pair a user with a Job Admin role on a specific job. Each row represents one `(user_id, job_id, role_id)` assignment; a user with access to multiple jobs appears in multiple rows. Site admins are not represented here — they have implicit access to every non-confidential job — so this endpoint only lists Job Admin grants. Filter with `user_ids`, `job_ids`, or `role_ids` to narrow the result set; combine with `/v3/future_job_permissions` (scope-based grants applied when matching jobs are later created) for the full picture of a user's job access. - [Create user job permission](https://harvestdocs.greenhouse.io/reference/post_v3-user-job-permissions.md): Grant a user a Job Admin role on a single job. The `role_id` must reference a Job Admin role; site admin and deprecated role types are rejected. Site admins already have access to every non-confidential job, so creating a user job permission for a site admin is a no-op and returns `204 No Content` instead of `201 Created`. To grant a role on jobs that don't exist yet, use `/v3/future_job_permissions` with an office and/or department scope instead. - [List user roles](https://harvestdocs.greenhouse.io/reference/get_v3-user-roles.md): User roles are the organization-wide dictionary of access levels a user can hold — the categories themselves, not the per-user assignments. Each role has a `role_type` of `job_admin` or `site_admin` and a display `name`; built-in roles ship as `Standard`, `Private`, and `Site Admin`, and customers may configure additional `job_admin` roles through the Greenhouse admin UI. The `id` returned here is the `user_role_id` used when assigning a user to a job through `user_job_permissions` (per-job grant) or `future_job_permissions` (office/department-scoped grant for jobs created later). - [List users](https://harvestdocs.greenhouse.io/reference/get_v3-users.md): Users are the Greenhouse accounts inside your organization — recruiters, hiring managers, interviewers, coordinators, sourcers, and site admins. Each user has a `primary_email` (sign-in identifier), an optional partner-supplied `employee_id` for HRIS linkage, an activation state (`deactivated`), and a `site_admin` flag indicating unrestricted organization-level access. Use `employee_ids`, `primary_email`, or `external_office_id`/`external_department_id` to look up users by external identifiers without an extra id round-trip. Integration system users (ISUs) and other service accounts are hidden by default — pass `show_service_accounts=true` to include them. - [Bulk update users](https://harvestdocs.greenhouse.io/reference/patch_v3-users-bulk.md): Update up to the bulk-endpoint cap of users in a single request. Pass an array of user payloads in `data`; each entry must include the target `id` plus the same patchable fields accepted by `PATCH /v3/users/{id}`. Each row is processed independently and the response reports per-row success or failure. Use for HRIS-driven backfills of `employee_id`, office/department reassignments, or job title updates across many users. - [Update user](https://harvestdocs.greenhouse.io/reference/patch_v3-users-id.md): Patch an existing user's profile fields. Only the keys included in the request body are modified; all other fields are left unchanged. Array assignments (`office_ids`, `department_ids`, `interviewer_tag_ids`) fully replace the existing set — pass an empty array to clear it. A `primary_email` update is only accepted when the new value is already a verified email address on the user's account. To toggle activation, site admin status, or job-level permissions, use the dedicated endpoints (`activate`, `deactivate`, `revoke_permissions`, `/v3/user_job_permissions`) rather than this one. - [Bulk activate users](https://harvestdocs.greenhouse.io/reference/post_v3-users-activate-bulk.md): Reactivate up to the bulk-endpoint cap of users in a single request. Pass an array of user ids in `data`; each id is processed independently and the response reports per-row success or failure. Equivalent to calling `POST /v3/users/{id}/activate` for each id but submitted as one request — use for HRIS-driven onboarding waves where many users return to active status together. - [Bulk create users](https://harvestdocs.greenhouse.io/reference/post_v3-users-bulk.md): Create up to the bulk-endpoint cap of users in a single request. Pass an array of user payloads in `data`, each matching the body shape of `POST /v3/users`. Each row is processed independently and the response reports per-row success or failure; rows that fail validation do not block the others. Use for HRIS-driven backfills or for provisioning a wave of new hires. - [Bulk deactivate users](https://harvestdocs.greenhouse.io/reference/post_v3-users-deactivate-bulk.md): Deactivate up to the bulk-endpoint cap of users in a single request. Pass an array of user ids in `data`; each id is processed independently and the response reports per-row success or failure. Equivalent to calling `POST /v3/users/{id}/deactivate` for each id but submitted as one request — use for HRIS-driven termination waves. - [Activate a user](https://harvestdocs.greenhouse.io/reference/post_v3-users-id-activate.md): Reactivate a previously deactivated user so they can sign in to Greenhouse and be assigned to new jobs again. The user keeps their prior job permissions, interviewer tags, and office/department assignments. Safe to call on a user that is already active — the response is `204 No Content` either way. Use this paired with `POST /v3/users/{id}/deactivate` for HRIS-driven lifecycle sync. - [Deactivate a user](https://harvestdocs.greenhouse.io/reference/post_v3-users-id-deactivate.md): Deactivate a Greenhouse user. The user can no longer sign in or be assigned to new jobs, but all of their historical activity (notes, scorecards, emails, applications they own) is preserved. Existing job permissions remain on the user record so they can be restored cleanly via `POST /v3/users/{id}/activate` if the user is later reinstated. Safe to call on a user that is already deactivated — the response is `204 No Content` either way. - [Revoke user permissions](https://harvestdocs.greenhouse.io/reference/post_v3-users-id-revoke-permissions.md): Demote a Site Admin to a Basic user, removing their organization-wide access. This also clears the user's existing per-job role grants (`user_job_permissions`). Safe to call on a user who is already a Basic user and still returns 204. Use `POST /v3/users/revoke_permissions/bulk` to demote multiple users in one call. - [Bulk revoke permissions](https://harvestdocs.greenhouse.io/reference/post_v3-users-revoke-permissions-bulk.md): Demote up to the bulk-endpoint cap of site admins to Basic users in a single request. Pass an array of user ids in `data`; each id is processed independently and the response reports per-row success or failure. Equivalent to calling `POST /v3/users/{id}/revoke_permissions` for each id but submitted as one request. Users that are not site admins are unaffected. - [Create user](https://harvestdocs.greenhouse.io/reference/post_v3-users.md): Create a new Greenhouse user in your organization. `first_name`, `last_name`, and `primary_email` are required; the user is created with the Basic permission level and no job assignments. Set `send_email_invite=true` to email the new user an invitation; leave it `false` (the default) when an HRIS sync is provisioning accounts ahead of the user's start date. Provide `employee_id` to link the new user to an HRIS record so subsequent calls can look the user up via `employee_ids`. Use `POST /v3/user_job_permissions` or `POST /v3/future_job_permissions` afterwards to grant the user Job Admin access on specific jobs or scopes.