---
name: greenhouse-oauth-app
description: Establishes which Greenhouse credential a connector actually needs and obtains it — Harvest v3 partner OAuth (issued only by Greenhouse Partner Support under a signed partnership agreement), customer-created Harvest v3 client-credentials, legacy Harvest v1/v2 API keys, Job Board tokens, Ingestion and Assessment partner keys — with scopes, the Site Admin rule, rate limits, IP allowlisting and a safe credential handoff. Use when asked to get Greenhouse OAuth credentials or API keys, register a Greenhouse app, become a Greenhouse integration partner, migrate a Greenhouse integration to Harvest v3, or fix a Greenhouse auth error like `unauthorized_client`, `invalid_scope`, a 403 on every list endpoint, or a connection that dies after two weeks. For any other vendor's developer portal, use that vendor's skill instead.
---

# Greenhouse API Credentials

**Read this first: Greenhouse has no self-serve developer portal where you register an app and walk away with a client
ID and secret.** There is no "create app" button for the redirect-based OAuth flow. Credentials for the Harvest v3
**Authorization Code** flow — the one a multi-tenant connector needs, where a customer clicks "Connect" and authorizes
you — are issued by hand, over email, by Greenhouse Partner Support, and only after a **signed Greenhouse partnership
agreement**. The partner program requires **at least one mutual customer** before it will consider you, and reviews
applications in a **monthly batch**. If the user's goal is "get Greenhouse OAuth credentials this afternoon," the
honest answer is that it is not available at any price without that partnership, and the run should stop at §4.

What *is* self-serve is different and worth understanding before you promise anything: **each individual customer can
create their own Harvest v3 (OAuth) credentials inside their own Greenhouse account** — a client ID and secret used
with the **client credentials** grant, no redirect, no consent screen, valid only for that one organization. A
platform can absolutely run on this: you ask each customer to generate a pair and paste it in. It is not OAuth as an
app-registration exercise; it is a per-tenant secret the customer hands you. Decide which of the two models you are
building against before doing anything else (§1) — most of the expensive mistakes here are people building the wrong
one.

Three more things that cost real time: the **Site Admin rule** (every list endpoint 403s unless the authorizing user
is a Site Admin — §6), **redirect URIs you cannot edit yourself** (§5), and the **v1/v2 sunset date that has already
passed** (§ Platform state).

## Inputs to collect before you start

Ask in one batch. Never invent.

| Input | Notes |
| --- | --- |
| **Which API surface** | Harvest, Job Board, Ingestion, Assessment or Onboarding — they do not share credentials (§1) |
| **Partner or custom** | Do you have a signed Greenhouse partnership agreement, or are you collecting per-customer credentials? (§1, §4) |
| **Integration name**, 128×128 logo | Shown to customers on the authorization screen; Partner Support asks for both (§4) |
| **Environment** | `testing` (your own sandbox only) or `production` (live for mutual customers) — you name this in the request |
| **Redirect URI(s)** | Every callback host, final, up front — changing them later is another email (§5) |
| **Scope set** | The exact `harvest:<resource>:<action>` strings (§6) |
| **A named mutual customer** | The partner program requires at least one; be ready to name them (§3) |
| **Static egress IPs** | Only if a customer turns on IP restriction for their credential (§7) |
| **Greenhouse tenant for testing** | A sandbox needs the right subscription tier (§3) |

## Quick Start

1. Establish which **API surface** and which **credential model** this actually needs (§1). Most wrong turns start here.
2. Confirm whether you already have credentials worth reusing — re-issuing orphans every existing connection (§2).
3. If partner OAuth: apply to the partner program and get the agreement signed. This gates everything else (§3).
4. Request credentials — by email for partner OAuth, or in the customer's Dev Center for per-customer keys (§4).
5. Register **every** callback host in that same request; you cannot self-serve them later (§5).
6. Pin down scopes *and* the authorizing user's Greenhouse permission level — both are required, neither substitutes (§6).
7. Check rate limits, sandbox access and IP restrictions before you promise a launch date (§7).
8. Verify with a real authorize → callback → refresh → refresh-again round trip (§8).
9. Hand the secret to a human, never to source control (§9).

## Platform state (verified 2026-09-20 — re-verify before trusting)

- **Harvest v1 and v2 were documented as "deprecated and unavailable after August 31, 2026."** That date is **in the
  past as of this writing**, yet Greenhouse's own support and developer docs still state it in the future tense and
  still document a v1/v2 → v3 transition path. **Do not assume either way.** Before planning work, test a v1/v2 Basic
  auth call against a real tenant and check the current text of the Harvest API overview article. If a customer's
  legacy API key still works, treat that as borrowed time, not as a supported path.
- **Harvest v3 is OAuth-only.** Greenhouse states plainly that once v1/v2 endpoints are gone, "OAuth will be the only
  supported authentication method for the Harvest API." Two grants, two audiences: **Authorization Code** for
  partners, **Client Credentials** for a customer's own integration.
- **A transition shim exists** (or existed): a v1/v2 API key can be exchanged at `https://harvest.greenhouse.io/auth/token`
  for a JWT usable as a Bearer token against `/v3`. Note the host — it is **not** the OAuth token endpoint
  (`https://auth.greenhouse.io/token`). Confirm this shim still answers before relying on it.
- **Partner OAuth credentials are issued by email**, by `partner-support@greenhouse.io`, after a signed partnership
  agreement. There is no portal, no console, and no way to self-register a client ID.
- **Scope changes are also an email.** Partners cannot edit their own scopes.
- **Customers self-serve their own credentials** in Configure → Dev Center → API Credential Management, choosing
  **Harvest** (v1/v2 key) or **Harvest v3 (OAuth)** (client ID + secret).
- The partner OAuth guide was last updated **2026-09-18** — two days before this verification, so it is current, and
  also a sign this area is actively changing.

If the Dev Center or the partner docs do not look like this, stop and report what you actually see.

## 1. Which API surface, and which credential

A reader arriving here is likely holding the wrong credential. Greenhouse runs several unrelated APIs and none of
their credentials interchange:

| Surface | Credential | Host | Who gets it |
| --- | --- | --- | --- |
| **Harvest v3** (core ATS read/write) | OAuth 2.0 — Authorization Code (partners) or Client Credentials (customers) | `harvest.greenhouse.io`, tokens at `auth.greenhouse.io` | Partners via agreement; customers self-serve |
| **Harvest v1/v2** (legacy) | API key, HTTP Basic, key as username with an **empty password** | `harvest.greenhouse.io` | Customer self-serve — but see Platform state |
| **Job Board** | **Board token** (public, in the job board URL) for all GET; a separate secret Job Board API key, Base64-encoded, only for the application-submission POST | `boards-api.greenhouse.io/v1/boards/` | Anyone; the token is not a secret |
| **Candidate Ingestion** (sourcing partners) | OAuth 2.0 *or* Basic with a Partner API Key plus an `On-Behalf-Of` email header | `api.greenhouse.io/v1/partner/`, OAuth at `api.greenhouse.io/oauth/authorize` and `/oauth/token` | Sourcing partners only, credentials issued by Greenhouse |
| **Assessment** (test providers) | Partner-issued API key, HTTP Basic; **Greenhouse calls you**, not the reverse; key must be under 171 characters | The partner's own endpoints | Assessment partners; the customer passes the key to their Greenhouse account manager |
| **Onboarding** | HTTP Basic (username + password); requires a Greenhouse Onboarding or Welcome subscription | separate product | Customers with that subscription; docs sit behind a login |

Two traps that follow directly from this table:

- **The Job Board token is not an API key.** It is public, it appears in the customer's job board URL, and it
  identifies the organization. Asking a customer for "your Greenhouse token" gets you one of the two, unpredictably.
  Ask for the board token and the Harvest credential by their full names, separately.
- **Ingestion and Assessment are separate integrations, not modes of Harvest.** A platform that supports more than one
  surface ships them as **separate connectors with separate credentials**. Do not try to make one Greenhouse app cover
  candidate ingestion and Harvest; the credentials, hosts and partner tracks are different.

> **Product fact — dated.** As of **2026-09-20**, Unified.to's Greenhouse connector authenticates in two ways against
> the Harvest API at `https://harvest.greenhouse.io/`: **OAuth 2.0** using the authorization endpoint
> `https://auth.greenhouse.io/authorize` and token endpoint `https://auth.greenhouse.io/token`, with client
> credentials carried as HTTP Basic on the token call and a `bearer {token}` API header; and an **API-key** mode
> using the legacy Basic scheme (key as username, empty password). Its OAuth scope set is the granular
> `harvest:<resource>:<action>` strings, grouped per unified object — for example candidates, applications, jobs,
> job posts, interviews, scorecards, notes, users, offices, departments, attachments and custom fields, each with
> `:list` for reads and `:create` / `:update` / `:destroy` for writes. Several write scopes are recorded as **not
> obtainable** from Greenhouse (scorecard writes in particular, and destroy on jobs, users and offices). The
> connector also asks each customer for a **Job Board token** as a second, separate input alongside the Harvest
> credential, and it treats access tokens as expiring in **one hour**. Separate connectors exist for the **Assessment**
> API and the **Ingestion** API, each with its own credential. **Confirm all of this with the connector's owner
> before acting on it** — connector configuration changes independently of this skill.

## 2. Reuse the existing credentials, or request new ones

Re-issued partner credentials mean a **new client ID, and every existing customer authorization is bound to the old
one** — every customer re-authorizes. Reuse what exists for: adding a redirect URI, changing scopes, rotating a
compromised secret, or diagnosing a failure. All four are handled on the existing client (§4, §5, §6).

Request a **new** client only when the user explicitly wants one: a separate product, a replacement for a compromised
client, or a deliberate move from Ingestion to Harvest. Say which path you are taking before you start.

For **per-customer** credentials the calculus is different and much gentler: each customer's pair is independent, so
rotating one affects exactly one tenant. Rotation there is a customer-side action with a built-in grace period (§4).

## 3. Accounts: partner program, and a tenant to test against

**The partner program** (`https://www.greenhouse.com/integration-partner`) is the gate for Authorization Code
credentials. What the run needs to know:

- **At least one mutual customer is required.** Not "helpful" — required. A pre-revenue product with no Greenhouse
  customer has no route in. An active website with a privacy policy is also required.
- **Applications are reviewed on the first Monday of each month** (first Tuesday if that is a holiday), with a
  response within about 7 business days of the review. Plan in months, not days. Urgent cases with a named mutual
  customer can request an out-of-cycle review via `partneronboarding@greenhouse.io`.
- Onboarding brings Partner Portal and sandbox access, then a build-and-submit-for-review step, then directory
  listing and co-marketing. Not every application is accepted.
- The agreement itself is a **business and legal decision**. Do not fill in revenue, volume, security or compliance
  claims on the user's behalf — collect the questions and hand them back.

**A tenant to test against.** Greenhouse sandboxes are gated by subscription tier (Greenhouse's support article
currently names the **Pro** tier; other internal notes describe it as an Expert-tier benefit — verify against the
customer's actual plan rather than either claim). A sandbox is created **empty**, not cloned from production, so you
add your own test data. Critically: **API keys, board tokens and job board URLs are not interchangeable between
sandbox and production.** Generate a separate set for each, and never assume a working sandbox credential says
anything about production.

Anything requiring a human — signing the agreement, email verification, two-factor enrolment, requesting a sandbox
from an account manager — hand back rather than looping.

**If this session has no browser automation** (the usual case for a CLI or cloud run), do not pretend to click. Give
the user an exact, ordered click path with the literal values to paste — the redirect URIs from §5 and the scope
strings from §6 — or a ready-to-send email body for §4, then continue once they report back with the client ID.

## 4. Obtaining the credentials

### Path A — Partner OAuth (Authorization Code), for a multi-tenant connector

There is no form. You email `partner-support@greenhouse.io`, **after** the partnership agreement is signed, with
exactly five things:

1. **Integration name** — the product name customers will recognize.
2. **Environment** — `testing` (your own sandbox only) or `production` (live for mutual customers). These are
   separate credential sets; ask for both if you need both.
3. **Required scopes** — the exact `harvest:<resource>:<action>` strings (§6). Ask for what you call today, not what
   you might call next year; adding scopes later forces every customer to re-authorize (§6).
4. **Redirect URI(s)** — every one, final (§5).
5. **A 128×128 logo file** — shown to customers on the authorization screen.

Greenhouse replies with a **Client ID** and **Client Secret**. Greenhouse's guide also asks you to confirm the final
working `redirect_uri` back to Partner Support once your callback endpoint is live — a step that is easy to skip and
leaves the registration half-configured.

**The flow itself**, once you hold credentials:

- Authorize: `GET https://auth.greenhouse.io/authorize` with `response_type=code`, `client_id`, `redirect_uri`,
  `scope` (space-separated), and `state` (documented as optional, but treat it as mandatory — it is your only CSRF
  defence here). **PKCE is not part of the documented flow.**
- Exchange: `POST https://auth.greenhouse.io/token`. Client authentication is **HTTP Basic** with
  `client_id:client_secret` Base64-encoded. Greenhouse's own examples pass `grant_type=authorization_code` and `code`
  as **query parameters on the POST with an empty body** — not as a form-encoded body. A client that only knows how
  to post a form body may fail here; verify which shape your client sends before blaming the credentials.
- Response: `{ token_type, access_token, refresh_token, expires_at }`. Note **`expires_at`** — an ISO-8601 timestamp,
  not the `expires_in` integer most OAuth clients expect. The client-credentials flow returns `expires_in` instead.
  A client that assumes one shape will mis-compute expiry against the other.
- Refresh: same endpoint, `grant_type=refresh_token` and `refresh_token`, again as query parameters with Basic auth.

**Lifetimes, all short, all load-bearing:**

| Token | TTL | What breaks |
| --- | --- | --- |
| Authorization code | **1 minute** | Any human step, queue hop or retry between callback and exchange kills it |
| Access token | **1 hour** | Routine; refresh proactively |
| Refresh token | **14 days**, and **rotated on every refresh** | An idle connection dies at day 15 and the customer must re-authorize from scratch |

The 14-day idle death is the single most common way a Greenhouse connection silently stops working. A connector that
only refreshes lazily — when a customer happens to trigger a sync — will lose every low-traffic tenant. Refresh on a
schedule. And **store the new refresh token from every refresh response**; a client that reuses the original fails on
the second refresh.

### Path B — Customer-created Harvest v3 (OAuth) credentials, client credentials grant

This is what a customer does in their own account, and the path available today without a partnership:

1. **Configure → Dev Center → API Credential Management → Create new API credentials.**
2. Choose API type **Harvest v3 (OAuth)**.
3. Save, then configure the scopes the integration needs (§6).
4. Greenhouse shows a **Client ID** and a **Client Secret**. **The secret is shown once**; the client ID stays visible.
5. Token: `POST https://auth.greenhouse.io/token`, HTTP Basic with `client_id:client_secret`, body
   `application/x-www-form-urlencoded` containing `grant_type=client_credentials` and optionally `sub=<user_id>`.
6. Call `https://harvest.greenhouse.io/v3/...` with `Authorization: Bearer <access_token>`. There is no refresh token
   — request a new access token when the old one expires or 401s.

Two details that decide whether this survives a year:

- **The `sub` parameter picks the acting user.** With no `sub`, requests act as the Integration Service User (ISU)
  auto-created with the credential. With `sub=<numeric user_id>`, they act as that user — and inherit that user's
  Greenhouse permissions, which is exactly how you hit the Site Admin rule in §6.
- **Create the credential from an ISU account, not a person's account.** Greenhouse says so explicitly: a credential
  tied to an individual dies when that individual is deactivated. This is the most common self-inflicted outage here.

**Rotation** is built in: the credential's client-secret tab generates a new secret and the old one remains usable for
up to about a week (Greenhouse also documents rotation as immediately invalidating the previous secret in one place
and offering a grace window in another — verify in the UI before you cut over, and keep a rollback). Revoking a
credential cuts access immediately for everyone using it; revoked credentials can be re-enabled.

### Path C — Legacy Harvest v1/v2 API key

Same Dev Center path, API type **Harvest**. The key is shown **once**. Used as HTTP Basic with the key as the username
and an **empty password** (so the header is Base64 of `KEY:` — the trailing colon is not optional, and omitting it is
a classic silent 401). Read the Platform state section before building anything new on this.

Creating or managing any of these requires a Greenhouse user at **Basic and above who can manage ALL organization's
API credentials**. A customer contact without that permission will see no Dev Center option and will report that the
feature "doesn't exist."

## 5. Redirect URLs

For **partner OAuth only** — the client-credentials path has no redirect.

Register **every** callback host in your initial request to Partner Support. You cannot add or edit them yourself;
each change is another email and another wait. For Unified.to these are one per data center — confirm the current list
with the platform owner rather than assuming:

```
https://api.unified.to/oauth/code          # us (default)
https://api-eu.unified.to/oauth/code       # eu
https://api-au.unified.to/oauth/code       # au
https://api-dev.unified.to/oauth/code      # dev
```

The `redirect_uri` you send must **match a registered value exactly**. A mismatch fails before the user ever sees a
consent screen, with an HTTP 400 and `{"error": "invalid_request", "error_description": "'redirect_uri=...' is not
configured for 'client_id=...'"}` — shown to your *customer*, as raw JSON, in their browser. Register the whole set on
day one; discovering a missing region later costs a review cycle, not a config change.

## 6. Scopes — and the permission rule that overrides them

Greenhouse scopes are granular and space-separated in the authorize URL, shaped `harvest:<resource>:<action>`:
`harvest:candidates:list`, `harvest:applications:create`, `harvest:jobs:update`, `harvest:attachments:destroy`,
`harvest:custom_fields:list`, and so on. Each endpoint in the Harvest v3 reference names the scope it requires; take
the strings from there rather than guessing the pluralization.

**Ask for the narrow set.** Not because Greenhouse polices it heavily, but because of the change mechanics:

- **Adding a scope requires every existing customer to re-authorize.** Existing tokens stay valid but never gain the
  new permission. This is a customer-visible migration, not a config tweak — the reason to get the scope list right in
  your first request to Partner Support.
- **Removing a scope takes effect immediately and globally**, enforced by a real-time check on every request, even for
  unexpired access tokens. Refresh tokens keep working and simply issue reduced tokens.
- **Partners cannot change their own scopes** — it is an email to `partner-support@greenhouse.io` every time.
- Some scopes are **not available at all.** Greenhouse partner support has told integrators that scorecard *write*
  scopes, and destroy on jobs, users and offices, cannot be granted. If a required capability comes back refused, that
  is a product answer, not a registration mistake — report it rather than retrying.

**The rule that outranks all of the above: scopes are necessary but not sufficient.** The authorizing user's
Greenhouse permissions cap what any token can do, and Greenhouse states that **all list endpoints require a Site Admin
authorizing user.** A connector that gets perfect scopes and a non-admin authorizer will 403 on effectively every read.
Some endpoints go further and require a specific job-level permission on top.

For **partner** connections the customer chooses at consent time between a **service-account authorization** (Site
Admins only; creates an organization-level service user that owns the connection and outlives any individual) and a
**user-linked authorization** (tied to that person; actions appear as theirs, and it dies with their account). For a
platform integration, **steer customers to the service account** — and note that only a Site Admin can pick it.
Customers manage and revoke these under **Configure → Dev Center → Connected Integrations**, which is also where you
send someone whose connection "just stopped."

## 7. Rate limits, IP allowlisting, sandbox, listing

- **Rate limits** are a **fixed 30-second window**, applied **separately for custom and partner integrations**, with
  token requests metered on their own **60-second** window. Greenhouse publishes no committed number — the documented
  example header shows `X-RateLimit-Limit: 75`, which is an illustration, not a guarantee. Read `X-RateLimit-Limit`,
  `X-RateLimit-Remaining` and `X-RateLimit-Reset` from **every** response and throttle from those. On `429`, honour
  `Retry-After` rather than retrying immediately. Do not hardcode a number from any blog post.
- **IP allowlisting is customer-controlled.** When creating credentials a customer may tick "Restrict access to
  specific IP addresses" and enter IPs or CIDR ranges; only those origins are then accepted. A security-conscious
  customer can therefore break your connector without telling you. If your egress is autoscaled or serverless with no
  stable addresses, surface this before launch — it is an infrastructure decision, not a support ticket.
- **Sandbox**: subscription-gated, empty on creation, with credentials and board tokens entirely separate from
  production (§3).
- **Listing**: directory inclusion, co-marketing and referrals come with the partner program, after an integration
  review. Greenhouse notes that not every marketplace integration uses Harvest v3, so the directory is not evidence of
  what any given partner is built on.

## 8. Verify end-to-end

Do not stop at "the token came back." Test what a customer's tenant actually does:

1. Authorize through your platform's real connect flow against a **second** organization — a sandbox or a mutual
   customer's tenant, not the one that built the credential.
2. Exchange the code **immediately**. If anything in your pipeline can delay it past 60 seconds, that is a bug now.
3. Confirm the token response shape your client parses (`expires_at` vs `expires_in`) matches the grant you used.
4. Make one real read — a list endpoint is the right choice precisely because it exercises the Site Admin rule.
5. **Refresh, then refresh again using the token returned by the first refresh.** This is what catches a client that
   ignores rotation, and it is a two-minute test for a failure that otherwise appears a day later.
6. Repeat step 4 as a **non-admin** user if any customer will connect as one. Expect a 403, and design for it.
7. Check `X-RateLimit-Remaining` on a real sync, not a single call.

| Symptom | Cause |
| --- | --- |
| HTTP 400, `unauthorized_client`, "not allowed to perform the authorization code grant" | Client ID exists but is not configured for this flow — Partner Support must fix it (§4) |
| HTTP 400, `redirect_uri ... is not configured` | Callback not registered exactly; shown to the customer as raw JSON (§5) |
| `?error=invalid_scope` on the redirect back | You requested a scope your client is not permitted to use (§6) |
| "Authorization code expired at ..." | More than 60 seconds between callback and exchange (§4) |
| "Authorization code has already been exchanged" | Double-submitted callback, or a retry after a successful exchange |
| 401 "not authorized to access 1 or more of the requested scopes" at exchange | The code carries scopes the client cannot request (§6) |
| **403 on every list endpoint, 200 on singletons** | Authorizing user is not a Site Admin (§6) — not a scope problem |
| 403 for one customer only | That customer's user permissions, or their IP restriction (§7) |
| Connection dies after a quiet fortnight | 14-day refresh-token TTL; refresh on a schedule (§4) |
| Second refresh fails, first succeeded | Client is not storing the rotated refresh token (§4) |
| Worked yesterday, 401 today, nothing changed | Customer rotated or revoked the credential, or the ISU/person the credential was tied to was deactivated (§4) |
| 401 on a legacy key that "looks right" | Missing trailing colon in the Basic header (`KEY:`) (§4 Path C) |
| Sandbox works, production 401s | Credentials and board tokens are not interchangeable across environments (§3) |
| `429` under normal load | 30-second fixed window; read the headers rather than guessing a number (§7) |

## 9. Hand off — never commit the key

- **Do not** write a client secret, API key, partner key or board API key into source control, a test, a fixture, a
  committed `.env`, a ticket, a PR body or a chat channel. Values go to the human running this, for their secret store
  or console. The Job Board *token* is public and may be recorded; the Job Board *API key* is not — keep them apart.
- If a code change is needed (a callback host, a scope string, a token-endpoint shape), keep it secret-free and say
  plainly what the human must set out of band.
- Report a secret once so it can be pasted into the secret store, say clearly that it is now in the transcript and can
  be rotated, then move on.
- Close with: which API surface and grant you ended up on; the client ID; where the secret was delivered; the
  authorize and token endpoints; the exact scope strings requested and any Greenhouse refused; the environment
  (testing vs production); the Site Admin / service-account requirement to pass to customers; the refresh cadence the
  14-day TTL demands; and whatever is still waiting on Greenhouse.

## Stop and ask

Hand back to a human rather than guessing when: **there is no signed partnership agreement** and the ask is
Authorization Code credentials (say so in the first reply — do not start a registration that cannot complete); the
partner application needs a named mutual customer, revenue, security or compliance claims; someone proposes
re-issuing partner credentials on a live integration (that re-authorizes every customer); a scope comes back refused
by Greenhouse; IP allowlisting requires decisions about static egress; a customer cannot find Dev Center (they lack
the credential-management permission); the v1/v2 sunset state on a live tenant contradicts the Platform state section;
or anything about Ingestion, Assessment or Onboarding is being treated as interchangeable with Harvest.

## References

- Greenhouse API overview (all surfaces) — https://support.greenhouse.io/hc/en-us/articles/10568627186203-Greenhouse-API-overview
- Harvest API overview and v1/v2 deprecation — https://support.greenhouse.io/hc/en-us/articles/360029266032-Harvest-API-overview
- Harvest v3 authentication (both grants, transition shim) — https://harvestdocs.greenhouse.io/docs/authentication
- Partner OAuth 2.0 Authorization Code guide — https://harvestdocs.greenhouse.io/docs/harvest-partner-oauth
- Generate token reference — https://harvestdocs.greenhouse.io/reference/generate-token
- Handling scope changes — https://harvestdocs.greenhouse.io/docs/handling-scope-changes
- Rate limiting — https://harvestdocs.greenhouse.io/docs/api-rate-limiting
- Create Harvest API credentials for an integration — https://support.greenhouse.io/hc/en-us/articles/5888163769883-Create-Harvest-API-credentials-for-an-integration
- Manage Harvest API credentials permissions — https://support.greenhouse.io/hc/en-us/articles/115000521723-Manage-Harvest-API-credentials-permissions
- Connect to Harvest v3 partner integrations (customer side) — https://support.greenhouse.io/hc/en-us/articles/41437121183899-Connect-to-Harvest-v3-partner-integrations
- Harvest v3 API migration overview — https://learn.greenhouse.io/harvest-v3-api-migration-overview
- READ endpoint migration guide — https://harvestdocs.greenhouse.io/docs/step-by-step-migration-instructions
- Harvest v3 API reference — https://harvestdocs.greenhouse.io/reference/get_v3-candidates
- Job Board API — https://docs.greenhouse.io/job-board.html
- Job board URL and board token — https://support.greenhouse.io/hc/en-us/articles/360020776251-Job-board-URL-for-Greenhouse-hosted-job-board
- Candidate Ingestion API — https://docs.greenhouse.io/candidate-ingestion.html
- Assessment API — https://docs.greenhouse.io/assessment.html
- Use a sandbox — https://support.greenhouse.io/hc/en-us/articles/17053185557787-Use-a-sandbox
- Greenhouse integration partner program — https://www.greenhouse.com/integration-partner
- Greenhouse APIs landing page — https://www.greenhouse.com/api
