API reference
Applicants
A person who applied. This is the cleanest population in Tahoe from a consent point of view — they came to your customer on purpose — and the endpoints say so explicitly.
GET/applicantsapplicants:read
Applicants in the workspace, newest first.
| Parameter | Type | Notes |
|---|---|---|
q | string | Search by name. |
updated_after | RFC 3339 | For incremental sync. |
limit | integer | Default 25, max 100. |
cursor | string | From the previous page. |
{
"object": "list",
"data": [
{
"object": "applicant",
"id": "apl_5Nx3jLm7Qd2s",
"workspace_id": "wsp_4Kd8sPm2Qx7L",
"full_name": "Priya Raman",
"location": "Seoul, KR",
"linkedin_url": "https://www.linkedin.com/in/priya-raman-1a2b3c",
"github_url": null,
"portfolio_url": null,
"created_at": "2026-09-02T14:21:09.115Z",
"updated_at": "2026-09-07T09:44:31.002Z",
"provenance": {
"origin": "applicant",
"acquisition": "inbound_application",
"provider": null,
"owner_workspace_id": "wsp_4Kd8sPm2Qx7L",
"first_seen_at": "2026-09-02T14:21:09.115Z",
"last_seen_at": "2026-09-07T09:44:31.002Z",
"consent": {
"basis": "candidate_submitted",
"candidate_facing_notice": true,
"unsubscribed": false,
"suppressed": false
},
"licence": {
"redistributable": false,
"note": "Submitted to one employer for one role. Not licensed for onward redistribution."
}
},
"external_refs": [],
"links": {
"self": "/api/partner/v1/applicants/apl_5Nx3jLm7Qd2s",
"applications": "/api/partner/v1/applicants/apl_5Nx3jLm7Qd2s/applications"
}
}
],
"has_more": true,
"next_cursor": "cur_eyJrIjoiMjAyNi0wOS0wMlQxNDoyMTowOVoi..."
}The provenance block
Every person-shaped resource in this API carries one, and it is not decoration — it is the field your compliance team keys on.
| Field | Meaning |
|---|---|
origin | Which population this person came from: applicant, sourced, shared_pool or ats_import. |
acquisition | How they arrived — e.g. inbound_application, provider_search. |
consent.basis | candidate_submitted, legitimate_interest_sourcing, public_profile or customer_provided. |
consent.candidate_facing_notice | Whether this person saw a notice at the moment their data was collected. True only for applicants. |
consent.unsubscribed | They asked not to be contacted. Honour it regardless of scope. |
consent.suppressed | They are under an erasure or suppression notice. |
licence.redistributable | Computed, and always false. |
external_refs
When the applicant arrived through an ATS connection, this carries the identifier in that system — exactly what an HRIS needs to dedupe against its own records without guessing on names.
"external_refs": [
{
"system": "greenhouse",
"type": "candidate",
"id": "48213097",
"connection_id": "ci_7Kd2mXq4Rp8v",
"link_origin": "import",
"last_synced_at": "2026-09-07T03:00:11.408Z"
}
]Match on system plus id. connection_id identifies your customer’s ATS connection rather than anything you should address, and an applicant created natively in Tahoe has an empty array.
GET/applicants/{applicant_handle}applicants:read
One applicant, same shape as a list row.
GET/applicants/{applicant_handle}/applicationsapplications:read
Every application this person has submitted in the workspace — the same objects as the applications endpoints. Note the scope: it is applications:read, not applicants:read, because the data returned is applications.
GET/applicants/{applicant_handle}/resumesresume:read
Every resume this person has submitted, across all their applications. Each row carries its own resume_access, so the same person can have one readable resume and one locked one.
GET/applicants/{applicant_handle}/contact-infocontact:read
Email addresses and, with contact:phone:read as well, phone numbers.
{
"object": "contact_info",
"subject": { "object": "applicant", "id": "apl_5Nx3jLm7Qd2s" },
"emails": [
{ "value": "[email protected]", "kind": "submitted", "status": "found" }
],
"phones": [],
"unsubscribed": false,
"field_states": {
"work_email": "found",
"personal_email": "not_found",
"phone": "found"
},
"restricted": ["phones"],
"restricted_reason": {
"phones": "scope_required:contact:phone:read"
}
}field_states is how you tell the two failure modes apart: not_found means Tahoe does not have that field, while a field named in restricted means Tahoe has it and you were not granted it. Storing the second as “no phone number” is the mistake the restricted contract exists to prevent.
An applicant’s contact details are candidate-submitted, so they are never paywalled — they gave them to your customer for this purpose. They are still personal data: each disclosed value consumes one unit of the daily budget and writes an audit row.
Related events
applicant.created, applicant.updated, applicant.deleted and applicant.unsubscribed, all under applicants:read. applicant.unsubscribed is the one to wire first — it is the event that stops you emailing someone who asked you not to.
