---
title: "Update offer"
method: PATCH
path: "/v3/offers/{id}"
tags: ["Offers"]
---

# Update offer

`PATCH /v3/offers/{id}`

## Request

- Base URL: `https://harvest.greenhouse.io`
- URL: `https://harvest.greenhouse.io/v3/offers/{id}`
- Auth: one of:
  - OAuth 2
    - Authorization code: `https://auth.greenhouse.io/authorize`
    - Client credentials
    - Token URL: `https://auth.greenhouse.io/token` scopes: `harvest:offers:update`
  - HTTP bearer

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`, `opening_id` (when your organization versions offers on opening changes), 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. `opening_id` must be an open opening on the application's job that no other unresolved offer holds, and can only be set to `null` when your organization doesn't require an opening on offers. `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. Offers carry private compensation data, so writing them is gated separately from the `harvest:offers:update` scope: when the access token includes a `sub` claim, the Site Admin it names must also hold the "See private notes, private fields, salary info, manage offers, request approval, and approve jobs/offers" advanced permission, or the request is rejected with `403 Forbidden`. Tokens issued without a `sub` claim act as your integration user and are not subject to it.

## Path parameters

- `id` integer, required

## Request body

- object
  - `starts_on` string, date: Candidate's proposed start date, in ISO 8601 (YYYY-MM-DD). Changing this on an existing offer typically creates a new offer `version`.
  - `opening_id` integer, nullable: Id of the opening this offer is for. Must be an open opening on the application's job that no other unresolved offer holds; otherwise the request fails with a 422. Send `null` to remove the opening, unless the organization requires an opening on offers. Changing the opening creates a new offer `version` when the organization is configured to version offers on opening changes. List the job's openings via `GET /v3/openings?job_ids={id}&open=true`.
  - `sent_on` string, date: Date the offer was sent to the candidate, in ISO 8601 (YYYY-MM-DD). Use to backfill the sent date for offers handled outside of Greenhouse.
  - `created_at` string, date: Date the offer was created, in ISO 8601 (YYYY-MM-DD). Use to backfill the original creation date for offers migrated from another system.
  - `resolved_at` string, date-time: Timestamp the offer was resolved (`Accepted` or `Rejected`), in ISO 8601. Updates are normalized to noon UTC on the date provided.
  - `custom_fields` union[]: Values for the offer's custom fields, including compensation components (base pay, equity, bonus, etc.). Each entry sets one custom field by name or id; only fields configured on the application's hiring plan apply. Replaces the listed fields wholesale — omit entries you do not want to modify. Harvest V3 does not evaluate calculated custom fields; if the organization hasn't enabled overriding that field, the request fails with a 422 naming it as not overridable.
    - union
      - object
        - `name_key` string, required: Required if custom_field_id is not provided. Exactly one of name_key or custom_field_id must be specified.
        - `custom_field_id` integer: Required if name_key is not provided. Exactly one of name_key or custom_field_id must be specified.
        - `value` union
          - string
          - string
          - string
          - string
          - string
          - boolean
          - number: User ID
          - union
            - number
            - string
          - union
            - string[]
            - number[]
          - number
          - object
            - `amount` number, required
            - `currency_code` string, required
            - `rationale` string
            - `frequency` string
          - object
            - `min_amount` number, required
            - `max_amount` number, required
            - `currency_code` string, required
          - object
            - `min_value` number, required
            - `max_value` number, required
      - object
        - `name_key` string: Required if custom_field_id is not provided. Exactly one of name_key or custom_field_id must be specified.
        - `custom_field_id` integer, required: Required if name_key is not provided. Exactly one of name_key or custom_field_id must be specified.
        - `value` union
          - string
          - string
          - string
          - string
          - string
          - boolean
          - number: User ID
          - union
            - number
            - string
          - union
            - string[]
            - number[]
          - number
          - object
            - `amount` number, required
            - `currency_code` string, required
            - `rationale` string
            - `frequency` string
          - object
            - `min_amount` number, required
            - `max_amount` number, required
            - `currency_code` string, required
          - object
            - `min_value` number, required
            - `max_value` number, required

## Response `200`

Successful

- object
  - `id` integer
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `version` integer: Revision number of this offer within its application. Greenhouse creates a new offer row (incrementing `version`) whenever a tracked field on an existing offer changes — typically `starts_on`, `opening_id`, or a custom field configured to trigger a new version. Pair with `current_only=true` to filter the list endpoint down to the latest version per application.
  - `application_id` integer: Id of the application this offer is extended on. Every offer belongs to exactly one application; the offer is voided if the application is rejected or deleted.
  - `job_id` integer: Id of the job this offer's application is on.
  - `candidate_id` integer: Id of the candidate (person) receiving this offer. Resolved through the offer's application.
  - `opening_id` integer, nullable: Id of the specific opening this offer is being extended for. `null` when the offer has not yet been linked to an opening.
  - `status` 'Created' | 'Accepted' | 'Rejected' | 'Deprecated': Lifecycle status of the offer. `Created` for offers still being drafted or pending approval, `Accepted` once the candidate accepts, `Rejected` if declined or withdrawn, and `Deprecated` for superseded prior versions (a new offer version replaces an earlier one with this status).
  - `starts_on` string, date, nullable: Candidate's proposed start date, in ISO 8601 (YYYY-MM-DD). `null` when no start date has been set on the offer.
  - `sent_on` string, date, nullable: Date the offer was sent to the candidate, in ISO 8601 (YYYY-MM-DD). `null` until the offer has been sent.
  - `resolved_at` string, date-time, nullable: Timestamp the offer was resolved (`Accepted` or `Rejected`), in ISO 8601. Date updates submitted through `PATCH /v3/offers/{id}` are normalized to noon UTC on the supplied date. `null` while the offer is still `Created` or has been superseded as `Deprecated` without a resolution.
  - `custom_fields` object, nullable

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `422`: Unprocessable Content

---

[API](https://skmtc.dev/greenhouse/apis/harvest-api.md) - [All operations](https://skmtc.dev/greenhouse/apis/harvest-api/llms.txt) - [OpenAPI document](https://skmtc.dev/greenhouse/apis/harvest-api/revisions/822822e3f771?raw)
