How to Export Data from Greenhouse: Methods, API Limits & Gaps
Complete guide to exporting data from Greenhouse: UI reports, Harvest API v3 rate limits, BI Connector, attachment expiry traps, and what data you can't get out.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
How to Export Data from Greenhouse: Methods, API Limits & Gaps
Greenhouse gives you several paths to get data out: UI-based CSV report exports, the Harvest API, the Business Intelligence Connector, and secondary methods including GDPR data exports and webhooks. The right method depends on whether you need a one-time snapshot, a recurring data pipeline, or a full-fidelity extraction that preserves the relational structure between Candidates, Applications, Jobs, and Scorecards.
The short version: Greenhouse offers two primary ways to get data out — manual CSV exports and the Harvest API. Manual exports work for one-off analysis. The Harvest API is what you use for automated, repeatable pipelines. The Business Intelligence Connector adds a third option for enterprise analytics. CSV exports flatten your data model, strip scorecard attribute ratings, and silently drop attachment files. The Harvest API preserves relational integrity but enforces aggressive rate limits. The BI Connector gives you raw SQL access but runs on a nightly cadence.
This guide covers every extraction method, the real API constraints, what data you can and can't get out, and where teams consistently lose data.
Harvest API v1 and v2 will be deprecated and unavailable after August 31, 2026. Make sure existing custom integrations use the latest version of Harvest (v3) by this date and any new integrations are developed with v3. Do not invest engineering time in v1/v2 extraction scripts.
Greenhouse Data Model: What You're Actually Exporting
Before choosing an extraction method, understand what's inside the system. Greenhouse's core data model follows this hierarchy: Candidate → Application → Job → Scorecard.
Greenhouse is strictly application-centric. A Candidate has a single profile containing basic contact information. But all pipeline stages, interview schedules, rejections, and offers are tied to the Application, not the Candidate. A candidate who applied for Software Engineer in 2022 and Engineering Manager in 2024 has two separate Applications with independent histories.
This relational chain — Candidate → Application → Job → Scorecard — is the first thing that breaks when you flatten to CSV.
Key entities you'll need to extract:
| Entity | What It Contains | Export Complexity |
|---|---|---|
| Candidates | Name, email, phone, tags, source, custom fields | Low |
| Applications | Status, rejection reason, current stage, applied-at timestamp, source | Medium |
| Jobs | Title, status, departments, offices, openings, hiring team | Low |
| Scorecards | Overall recommendation, attribute ratings, questions, interviewer, submitted_at | High |
| Attachments | Resumes, cover letters, work samples | High (signed URLs) |
| Offers | Offer details, status, start date, custom offer fields | Medium |
| Activity Feed / Notes | Recruiter notes, emails, internal comments | High |
| Custom Fields | Org-specific fields at candidate, application, job, and offer level | Medium |
Any extraction plan should start with a decision about whether you need the relational chain intact. If you do, CSV exports are off the table.
Method 1: UI Report Exports (CSV)
How It Works
Greenhouse's built-in reporting lets you run essential reports (pipeline, time-to-hire, source effectiveness) and custom reports, then export results as CSV or Excel. Recipients receive an email containing the report data, a link to view the report in Greenhouse Recruiting, and a downloadable .csv version of the report. You can also schedule a report email at a regular cadence. Scheduling options include weekly, bi-weekly, monthly, and quarterly frequency.
The in-app essential candidate report is limited to 1,000 candidate applications, and its grain is the application row, not the full candidate-to-application relationship model. (support.greenhouse.io)
Greenhouse also offers a Report Connector that pulls reports into Google Sheets with automatic refresh. Refreshes overwrite the sheet's imported data, making it useful for live dashboards but not as a system of record. (support.greenhouse.io)
What You Get
- Candidate lists with basic profile fields
- Pipeline snapshots filtered by job, department, or office
- Source attribution data
- Custom field values (if included in the report configuration)
What You Lose
- Scorecard attribute-level ratings — CSV reports capture overall recommendation but flatten or omit per-attribute scores
- Relational IDs — the Candidate → Application → Job chain is collapsed into rows, with no reliable foreign key to rejoin them
- Attachments — resumes and documents are not included in CSV exports
- Activity feed / notes — not available through standard report exports
- Interview scheduling details — panel composition, times, feedback links
One additional trap: if you need candidate responses to custom application questions for a specific job post, you must choose Email as XLS. The standard in-app view does not include those responses. (support.greenhouse.io)
When to Use It
One-off analysis, ad-hoc stakeholder reporting, or small-scale audits. Not viable for migration, data warehouse pipelines, or anything requiring relational integrity. If you're performing a full system migration — like a Greenhouse to Lever migration or a Greenhouse to Ashby migration — CSV exports are insufficient.
Greenhouse has introduced "Download candidate data" and "Export reports" permissions that give organizations more control over how personal candidate information is shared outside the platform. If your export plan starts failing for some users and not others, check permissions before debugging code.
Method 2: Harvest API v3 (Full Programmatic Export)
The Harvest API is Greenhouse's primary extraction interface. It is designed to export internal candidate and job information from Greenhouse Recruiting via GET endpoints, and also includes POST, PUT, PATCH, and DELETE endpoints to transform information in Greenhouse Recruiting.
Authentication and Versioning
Harvest v1/v2 (deprecated August 31, 2026): Uses Basic Auth over HTTPS. The username is your Greenhouse API token and the password should be blank.
Harvest v3 (current): Requires Bearer Authorization over HTTPS, using a valid JWT access token. Harvest v3 also supports the full OAuth2 authorization code flow for partner integrations that connect to multiple Greenhouse accounts.
Scopes are granular — for example, harvest:applications:list to read applications, harvest:candidates:create to create candidates. List endpoints require a Site Admin authorizing user.
JWT token expiry: Greenhouse v3 access tokens expire after 1 hour (3,600 seconds). Your extraction pipeline must implement token refresh logic — either proactively before expiry or reactively on a 401 response — rather than using a long-lived secret. Store your refresh token separately and treat it as a privileged credential.
# v3 Bearer token request
curl --location 'https://harvest.greenhouse.io/v3/candidates?per_page=100' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'Rate Limits
This is where most extraction scripts break. Greenhouse enforces rate limits in unusually short windows.
| API Version | Rate Limit | Window | Throttle Response |
|---|---|---|---|
| Harvest v1/v2 | 50 requests | Per 10 seconds (rolling) | HTTP 429 |
| Harvest v3 | 75 requests (observed) | Per 30 seconds (fixed) | HTTP 429 |
| v3 Token Issuance | Throttled separately | Per 60 seconds | HTTP 429 |
| Audit Log API | 3 requests (additional sub-limit) | Per 30 seconds | HTTP 429 |
Important: Greenhouse does not publish a single universal v3 rate limit number in its documentation. The 75-per-30-second figure is derived from observed X-RateLimit-Limit response headers during live extractions and from documented examples in Greenhouse's developer materials — but Greenhouse reserves the right to adjust it. Some endpoints carry their own sub-limits independent of the general limit.
Build your rate limiter to read the X-RateLimit-Limit and X-RateLimit-Remaining response headers dynamically rather than hardcoding a number. Use exponential backoff starting at 1 second with a maximum of 30 seconds on any HTTP 429 response.
Rate limits are per API key, not per endpoint — two scripts sharing one key will collide. If you're running parallel extraction jobs (e.g., one for candidates, one for scorecards), use separate API keys or serialize requests through a single queue.
At the documented example rate of 50 requests per 10 seconds with 500 records per page, a nightly export of a 10,000-candidate org takes under a minute of request time for candidate records alone. Rate limits are not the primary bottleneck for structured data — attachments are.
Pagination
v1/v2: Paginated results include a Link (RFC-5988) response header with next, prev, and last URLs. Max per_page is 500.
v3: Harvest v3 uses cursor-based pagination for list endpoints. v3 currently returns only a next link — no prev or last. You cannot calculate total result counts or jump to arbitrary pages. Follow the rel="next" URL from the response Link header until it's absent.
Critical cursor rule: For v3, the cursor parameter must not be combined with other filter parameters. Apply your filters (created_at, updated_at, status) on the first request only.
# v3 cursor-based pagination — first request with filters
curl 'https://harvest.greenhouse.io/v3/candidates?updated_at[gte]=2026-01-15T00:00:00Z&per_page=500' \
-H 'Authorization: Bearer TOKEN'
# Response Link header:
# Link: <https://harvest.greenhouse.io/v3/candidates?cursor=abc123>; rel="next"
# Subsequent requests — use the cursor URL directly, no additional params
curl 'https://harvest.greenhouse.io/v3/candidates?cursor=abc123' \
-H 'Authorization: Bearer TOKEN'Key Endpoints for Data Extraction
| Endpoint | Returns |
|---|---|
GET /v3/candidates |
Candidate records with profile fields and application IDs |
GET /v3/applications |
Application records with status, stage, job ID, rejection reason |
GET /v3/jobs |
Job records with departments, offices, openings, hiring team |
GET /v3/scorecards |
Scorecards with attribute ratings, questions, interviewer |
GET /v3/offers |
Offer records with custom fields |
GET /v3/scheduled_interviews |
Interview schedule with panel and times |
GET /v3/custom_fields |
Custom field definitions |
GET /v3/sources |
Source definitions for attribution |
v3 list endpoints support created_at and updated_at filters with operators gte, lte, gt, and lt. Do not use both created_at and updated_at filters simultaneously on the same request.
Scorecard API Response Structure
Scorecards are the most complex entity to extract. A truncated v3 scorecard response looks like this:
{
"id": 4897232,
"application_id": 19284756,
"interviewed_at": "2026-01-10T14:00:00.000Z",
"submitted_at": "2026-01-10T16:32:00.000Z",
"submitted_by": {
"id": 834921,
"name": "Jane Doe",
"employee_id": "EMP-0042"
},
"overall_recommendation": "yes",
"attributes": [
{
"name": "Communication",
"type": "Skills",
"note": "Articulates trade-offs clearly.",
"rating": "yes"
},
{
"name": "Problem Solving",
"type": "Skills",
"note": "Strong first-principles approach.",
"rating": "strong_yes"
}
],
"ratings": {
"strong_yes": ["Problem Solving"],
"yes": ["Communication"],
"mixed": [],
"no": [],
"strong_no": []
},
"questions": [
{
"id": 98234,
"question": "Describe a system you designed under constraint.",
"answer": "Redesigned the ingestion pipeline to handle 10x load..."
}
]
}Key fields for extraction:
application_id— the foreign key linking scorecards back to applicationsattributes [].rating— per-attribute rating values:strong_yes,yes,mixed,no,strong_nooverall_recommendation— the top-level interviewer decisionquestions [].answer— free-text interview notes, often the highest-value qualitative data
Attribute ratings are not present in CSV exports — you must use the API to get them.
The Attachment Trap
This is the single most common data-loss failure mode in Greenhouse exports.
Resumes, cover letters, and other document attachments in Greenhouse are hosted on Amazon Web Services and provided via signed, temporary URLs. These URLs expire after 7 days from the time of API retrieval, per Greenhouse's developer documentation. Users should download these documents immediately after the request is made and should not rely on these URLs to be available for future requests.
Greenhouse doesn't provide a bulk download feature. You must iterate through candidates or applications via API, extract each attachment URL, and download the file immediately.
import requests
import time
def download_attachments(candidate, output_dir):
for attachment in candidate.get('attachments', []):
url = attachment.get('url')
filename = attachment.get('filename', f"attachment_{attachment.get('id', 'unknown')}")
if url:
resp = requests.get(url, stream=True)
with open(f"{output_dir}/{filename}", 'wb') as f:
f.write(resp.content)
time.sleep(0.2) # Stay within rate limitsAttachment type visibility rules: Not all attachment types are equally accessible. Resumes and cover letters are broadly accessible to users with candidate access. Offer packets, signed offer documents, and private documents have narrower access restrictions. Ensure your API key's associated user has the necessary permissions for each attachment type before assuming completeness.
In the event AWS S3 is experiencing issues, document attachments will not be available in Harvest. Plan for retry logic on attachment downloads — S3 outages and transient errors will cause silent data loss if you don't handle them. Implement at least 3 retries with exponential backoff before marking an attachment as failed.
Method 3: Business Intelligence Connector
The Business Intelligence Connector (BIC) is Greenhouse's warehouse export. Greenhouse delivers your data nightly to Amazon S3 or Amazon Redshift, spanning data from the creation of your environment. (support.greenhouse.io)
Greenhouse's own guidance is to use BIC for advanced reporting and APIs for real-time transactional integrations. (support.greenhouse.io)
Pros:
- No rate limits. You query the data using standard SQL.
- Historical stage transitions. You get access to underlying tables that are difficult to reconstruct via the REST API, including timestamps for each stage transition.
- Zero extraction code. No pagination or retry logic required.
Cons:
- Cost. BIC is an expensive add-on, available on Plus and Pro tiers.
- Latency. Data is refreshed once every 24 hours. Not suitable for same-minute provisioning, trigger-based automation, or cutover-day delta syncs.
- Schema complexity. The BIC schema is highly normalized, requiring complex SQL joins to reconstruct a candidate's full profile.
BIC Table Reference
The core BIC tables and their grain:
| Table | Grain | Notes |
|---|---|---|
candidates |
One row per candidate | Snapshot; PII tables (email, phone, address) are opt-in |
applications |
One row per application | Latest-status snapshot only — no historical records |
jobs |
One row per job | Includes departments, offices, openings |
scorecards |
One row per scorecard | Includes attribute-level ratings |
custom_fields |
One row per field definition | Separate value tables per entity type |
demographic_answers |
One row per answer | Excludes EEOC responses |
stage_transitions |
One row per transition event | Historicized — this is the primary advantage over the REST API |
Critical BIC schema notes:
- The
applicationstable is a latest-status snapshot — Greenhouse explicitly documents that it does not contain historical records. If you need application history over time, you must build your own snapshot layer on top of daily BIC exports. - Candidate email, mailing address, and phone number tables are opt-in and must be explicitly enabled in BIC configuration.
- The
demographic_answerstable excludes EEOC responses. If your compliance or DEI reporting requires EEOC data, you must extract it separately via the Harvest API (GET /v3/applications/{id}/demographics). - Joining scorecards to candidates requires:
scorecards → applications (via application_id) → candidates (via candidate_id). There is no directcandidate_idon thescorecardstable.
If your goal is building internal dashboards in Tableau or Looker, the BI Connector is the best choice. If your goal is migrating data to a new ATS — see our Greenhouse to Workday migration guide — the Harvest API is preferred because it returns JSON that maps more directly to target system schemas.
Other Export Paths: GDPR Exports, Webhooks, and Third-Party Tools
GDPR Data Subject Request Export
Companies need to provide candidate data upon request in an efficient and easy format. Greenhouse has built a feature to respond to and complete data requests from candidates. You can configure what data should be accessible and send it to candidates in a CSV file by clicking a button on their profile.
This is designed for compliance, not bulk extraction. It exports a single candidate's data — useful for GDPR Article 15 access requests but not a viable method for migration or analytics.
Candidate packets serve a similar one-person purpose: configured in admin settings and downloaded from a candidate profile. If a packet includes private data, only users with private data access can download it. (support.greenhouse.io)
Webhooks for Real-Time Sync
Greenhouse supports webhooks for candidate and job events. Below is the complete list of supported webhook events versus notable gaps:
Supported webhook events:
| Event | Trigger |
|---|---|
application_updated |
Application status changes |
candidate_stage_change |
Candidate moves to a new pipeline stage |
candidate_hired |
Recruiter clicks "Mark Candidate as Hired" |
offer_created |
New offer created |
offer_updated |
Offer details modified |
offer_deleted |
Offer removed |
job_post_created |
New job posting published |
job_post_updated |
Job posting modified |
delete_candidate |
Candidate profile deleted |
Notable missing webhook events:
| Missing Event | Impact |
|---|---|
candidate_created |
Cannot trigger on new candidate entry without polling |
interview_scheduled |
No push notification when interviews are booked |
scorecard_submitted |
Must poll for new scorecard submissions |
application_created |
New inbound applications require polling to detect |
note_created |
Activity feed additions are not pushed |
These gaps mean a webhook-only strategy will miss significant event categories. For complete coverage, use webhooks for supported events plus a nightly full-diff poll for unsupported ones.
The candidate hired webhook fires each time someone clicks "Mark Candidate as Hired" and includes candidate, job, offer, and custom field data. It's a useful forward-sync mechanism for HRIS provisioning but does not replace a historical backfill. (support.greenhouse.io)
Third-Party Integration Platforms
Several iPaaS tools offer pre-built Greenhouse connectors that wrap the Harvest API:
- Celigo — Greenhouse connector enables automating applicant and candidate workflows and connecting with other human resource management systems.
- Skyvia — Load data from Greenhouse to CSV files with no code; exports Applications, Candidates, Jobs, etc. automatically on a schedule.
- Fivetran / Improvado — ELT connectors that replicate Greenhouse data into cloud warehouses.
These tools abstract away pagination and rate-limit handling but still operate within the same Harvest API constraints. They won't give you data the API doesn't expose. They're a good fit for low-code teams who need simple scheduled exports, but offer less control over attachment downloads and edge-case handling.
What Data Can't You Export from Greenhouse?
No export method gives you everything. Here's what's missing or incomplete:
| Data | Export Gap |
|---|---|
| Email thread content | Not available via Harvest API — only email metadata (timestamps, subject line) |
| Greenhouse internal analytics | Calculated metrics (time-in-stage, pass-through rates) are report-level aggregations, not raw exportable fields |
| User permission configurations | Org-level role/permission settings are not exposed via API |
| Deleted records | Once a candidate or application is deleted, it's gone from the API — no soft-delete or archive endpoint |
| Interview kit templates | Kit configurations are readable but the template structure does not fully export |
| Workflow/automation rules | Stage-transition automations, auto-advance rules, and approval chains are not API-accessible |
| Candidate photos | Candidate photos have been removed from Greenhouse and will no longer be accepted |
| Third-party assessment artifacts | Take-home tests submitted through some partner integrations live behind a URL on the partner platform, not in Greenhouse attachments |
| EEOC demographic responses | Excluded from BIC demographic_answers table; accessible only via GET /v3/applications/{id}/demographics |
If you're migrating to another ATS, the workflow and automation gap is significant — you'll need to manually recreate stage configurations, approval flows, and email templates in your target system.
Building a Full Greenhouse Export Pipeline
Here's the extraction sequence we use for migration-grade exports:
Step 1: Inventory and Scope
Pull custom field definitions first (GET /v3/custom_fields). This tells you the shape of your data before you start extracting records. Count candidates, applications, and jobs to estimate total API calls and time. At 500 records per page, a 50,000-candidate org requires a minimum of 100 paginated requests for candidates alone — more if you're filtering by date range.
Step 2: Extract Reference Data
Export lookup tables before transactional data:
- Jobs (with departments, offices, openings)
- Sources
- Users (interviewers, recruiters, coordinators)
- Custom field option sets
- Rejection reasons
- Demographic question and answer definitions
These are small payloads with high join value. Without them, you'll have orphaned IDs in your candidate and application records that you can't decode downstream.
Step 3: Extract Candidates and Applications
Use updated_at filters for incremental extraction. On the first run, pull everything. On subsequent runs, pull only records updated since the last checkpoint.
# Incremental extraction pattern
last_sync = load_checkpoint() # e.g., "2026-01-15T00:00:00Z"
url = f"https://harvest.greenhouse.io/v3/candidates?updated_at[gte]={last_sync}&per_page=500"
while url:
resp = requests.get(url, headers=auth_headers)
if resp.status_code == 429:
time.sleep(exponential_backoff())
continue
if resp.status_code == 401:
auth_headers = refresh_token() # JWT expiry — renew and retry
continue
process_candidates(resp.json())
# Download attachments inline — don't defer
for candidate in resp.json():
download_attachments(candidate, output_dir)
url = parse_next_link(resp.headers.get('Link'))
save_checkpoint(datetime.utcnow().isoformat())Recommended extraction order: jobs/openings → field dictionaries → candidates → applications → offers → attachments → notes → scorecards. That ordering minimizes foreign-key misses and makes validation less painful.
Step 4: Extract Scorecards and Interview Data
Scorecards are the highest-value, highest-complexity data. Each scorecard includes attribute-level ratings (see JSON structure above), free-text responses, and interviewer metadata. Pull them via GET /v3/scorecards and match to applications using application_id.
Filter by updated_at for incremental runs. Note that a scorecard's updated_at changes when an interviewer edits their feedback after initial submission — your pipeline should upsert, not insert-only.
Step 5: Download Attachments Synchronously
Do not store URLs for later download. Download each file as you encounter its URL. Store files with a naming convention that preserves the Candidate ID → Application ID → Attachment ID chain:
/{candidate_id}/{application_id}/{attachment_id}_{filename}
This naming convention makes it possible to reassemble the relational structure from the file system alone if your database metadata is lost.
Step 6: Validate
Compare record counts between Greenhouse UI reports and your extracted dataset. Check for:
- Missing scorecards (common when API key permissions restrict access to certain interview types)
- Orphaned applications (candidate deleted but application record cached in your extract)
- Attachment download failures (S3 errors, expired URLs on retry)
- Null PII fields (GDPR-anonymized candidates — see below)
Edge Cases That Break Greenhouse Exports
Custom Fields
Greenhouse allows administrators to create custom fields on Jobs, Candidates, Applications, and Offers. In the API payload, these appear in a custom_fields object keyed by field name. Administrators can change the names or types of these fields over time, which means the same key may represent different data across time periods. Your extraction script must dynamically inspect the field metadata (GET /v3/custom_fields) rather than hardcoding field names. Without the field definition metadata, you can't interpret the values in candidate or application records.
Merged Candidates
Recruiters frequently merge duplicate candidate profiles. When this happens, Greenhouse retains the primary candidate ID and aliases the secondary ID. If your extraction script uses a list of historical candidate IDs (from a previous snapshot, for example), it will throw HTTP 404 errors when attempting to fetch profiles that have been merged into another record. Always check for merged candidate references and resolve aliases before treating a 404 as a missing record.
GDPR-Anonymized Candidates
When a candidate is anonymized for GDPR or CCPA compliance, their PII is scrubbed, but historical application data remains for reporting purposes. Here is what the API returns for each field type after anonymization:
| Field | Anonymized Value |
|---|---|
first_name |
null |
last_name |
null |
email_addresses |
[] (empty array) |
phone_numbers |
[] (empty array) |
addresses |
[] (empty array) |
tags |
[] (empty array) |
application.status |
Preserved |
application.rejection_reason |
Preserved |
scorecard.overall_recommendation |
Preserved |
Your extraction schema must define all PII fields as nullable and your downstream system must handle empty arrays gracefully. A common failure mode is a database NOT NULL constraint on email that causes inserts to fail for anonymized candidates, silently dropping their application records from your extract.
Greenhouse Recruiting allows organizations to control the data retention timeframe, data to be deleted, and notifications on a per-office basis with Data Retention Rules. If you're extracting data near the end of a retention window, records may be auto-deleted before your export completes — run your extraction in a single continuous session rather than spread across days.
Private Notes and API Security
Private candidate notes can be accessed via the Harvest API as long as the credential has the relevant Activity Feed access, regardless of the end user's in-app permissions. This means an API key can retrieve notes that the human user associated with the key cannot see in the UI.
Pair that with attachment visibility rules — offer packets, signed offer documents, and private documents have narrower access than resumes or cover letters — and the takeaway is: treat export credentials as privileged infrastructure, not convenience keys. Scope API keys to the minimum required permissions and audit who has access to them. (support.greenhouse.io)
The On-Behalf-Of Header
All write operations (POST, PATCH) require an On-Behalf-Of: <greenhouse_user_id> header referencing an active Site Admin. Omitting it returns a 403. This matters if your export pipeline also writes back data (tags, notes, or status updates) during extraction — a common pattern in migration tooling that applies tags to mark records as exported.
Third-Party Assessment Artifacts
Take-home tests submitted through some third-party integrations are not added to the candidate's Greenhouse attachment list. The results live behind a URL on the partner platform. If your migration scope includes assessment artifacts, query each partner integration's API separately — do not assume every file associated with a candidate lives in Greenhouse. (support.greenhouse.io)
GDPR and CCPA Considerations
Exporting candidate data from Greenhouse triggers compliance obligations regardless of extraction method. The GDPR regulates the exportation of personal data outside of the European Union. Whether or not you are geographically located within the EU, GDPR impacts your organization as long as you are processing and storing personal data of individuals who live there.
Greenhouse-specific GDPR fields and their API locations:
| Data Type | API Location | GDPR Classification |
|---|---|---|
| Name, email, phone | GET /v3/candidates — top-level fields |
Personal data (Art. 4) |
| IP address (application) | application.location.address |
Personal data |
| GDPR consent status | candidate.gdpr_consents [] |
Consent record (Art. 7) |
| Anonymization status | candidate.anonymized (boolean) |
Processing restriction (Art. 18) |
| Demographic answers | GET /v3/applications/{id}/demographics |
Special category (Art. 9) if race/ethnicity included |
Practical implications:
- Data minimization: Don't export more than you need. If migrating, define a cutoff date — candidates older than 2–3 years with no activity often fall outside retention policy.
- Right to erasure: People have the "right to be forgotten" and Greenhouse customers are required to erase a candidate's personal data when requested. If you export data and then receive an erasure request, you must delete it from your export destination too — your target system or data warehouse is not exempt.
- Consent status: Export the
gdpr_consentsarray alongside candidate records. Greenhouse tracks consent type, consent date, and consent source at the candidate level. Losing this during migration means you cannot demonstrate lawful basis for processing in the target system. - Cross-border transfer: If your export destination is outside the EU, ensure appropriate transfer mechanisms (Standard Contractual Clauses, adequacy decisions) are in place before the export begins — not after.
- Anonymized candidate handling: Your target system must import anonymized candidates as anonymized. Do not reconstruct PII from backups or cached data for candidates who have been anonymized in Greenhouse.
For a deeper dive, see our GDPR & CCPA compliance guide for candidate data migration.
Choosing the Right Extraction Method
| Scenario | Recommended Method |
|---|---|
| One-time report for stakeholders | UI CSV export |
| Recurring spreadsheet analysis | Report Connector to Google Sheets |
| Warehouse analytics pipeline | Business Intelligence Connector |
| Full ATS migration | Harvest API v3 (full extract + attachments) |
| Individual GDPR data request | Built-in GDPR export or candidate packet |
| Low-code team, simple sync | Third-party connector (Celigo, Skyvia, Fivetran) |
| Real-time event capture | Webhooks + nightly API poll |
| Downstream HRIS hire sync | Candidate hired webhook or accepted-offer polling |
| EEOC demographic data | Harvest API only — not available in BIC |
| Historical stage transition data | Business Intelligence Connector (stage_transitions table) |
For migrations specifically, the API-based path is the only one that preserves scorecard attribute ratings, attachment files, and the full Candidate → Application → Job relational chain. CSV exports will always lose fidelity. For migration-specific patterns, see our guides for Greenhouse to Lever, Greenhouse to Ashby, and Greenhouse to Workday.
Frequently Asked Questions
- How do I export all candidate data from Greenhouse?
- Use the Harvest API v3 to programmatically extract candidates, applications, scorecards, and attachments via GET endpoints. UI CSV exports only capture flat candidate lists without relational data, scorecard attribute ratings, or resume files. Authenticate with OAuth 2.0 Bearer tokens and paginate using cursor-based Link headers.
- What are the Greenhouse Harvest API rate limits?
- Harvest v1/v2 allows 50 requests per 10-second rolling window. Harvest v3 uses a 30-second fixed window with 75 requests as the documented example limit. Token issuance is throttled separately on a 60-second window. Some endpoints like the Audit Log API have additional sub-limits. Exceeding limits returns HTTP 429.
- Can I bulk download resumes from Greenhouse?
- No. Greenhouse does not provide a native bulk resume download feature. Resumes are served as signed AWS S3 URLs that expire after 7 days. You must use the Harvest API to iterate through candidate or application records and download each attachment file immediately — storing URLs for later will result in dead links.
- Is Greenhouse Harvest API v1 being deprecated?
- Yes. Greenhouse Harvest API v1 and v2 will be deprecated and unavailable after August 31, 2026. All new integrations should use Harvest v3 with OAuth 2.0 authentication. Existing v1/v2 integrations using Basic Auth must be migrated to v3 before the deadline.
- What data can't be exported from Greenhouse?
- Email thread content (only metadata is available), internal analytics calculations, user permission configurations, deleted records, workflow automation rules, stage-transition automations, approval chains, and third-party assessment artifacts that live on partner platforms are not accessible via the Harvest API or CSV exports. Candidate photos have been permanently removed from the platform.