---
title: JOIN API Integration on Truto
slug: join
category: ATS
canonical: "https://truto.one/integrations/detail/join/"
---

# JOIN API Integration on Truto



**Category:** ATS  
**Status:** Beta

## MCP-ready AI tools

Truto exposes 30 tools for JOIN that AI agents can call directly.

- **list_all_join_jobs** — List jobs in Join. Truto sends status=ONLINE,OFFLINE,ARCHIVED and content=true by default (every job, with its full content); pass status or content to override (JOIN's own defaults are ONLINE and false). Returns each job's id, createdAt, lastUpdatedAt, title, status, externalId, and office.
- **get_single_join_job_by_id** — Get a single job in Join by id. Returns the job including id, createdAt, lastUpdatedAt, title, status, externalId, office, workplaceType, and screening questions.

JOIN's reference says description, salary, contact, contactPerson, attachments, employmentTypeId, categoryId, seniorityId, language, and followers are returned only when content=true, yet documents no content parameter for this endpoint, so they may be absent. Required: id.
- **create_a_join_job** — Create a job in Join; new jobs are automatically set active and multiposted to job boards. Returns: id. Required: title, description, categoryId, language, employmentTypeId, officeId.
- **update_a_join_job_by_id** — Update a job in Join by id; all body fields are optional. Returns: id. Required: id.
- **join_jobs_bulk_change_status** — Change the status of a job in Join to ONLINE, OFFLINE, or ARCHIVED. Returns: id. Required: job_id, status.
- **join_jobs_activate** — Activate an archived job in Join. Once activated, the job is multiposted on job boards again. Returns: id. Required: job_id. This endpoint is deprecated; if the job is already active, an error is raised but the job remains active.
- **join_jobs_archive** — Archive an active job in Join. Once archived, the job is no longer multiposted on job boards. Returns: id. Required: job_id. This endpoint is deprecated; if the job is already archived, an error is raised but the job remains archived.
- **list_all_join_applications** — List applications in Join with filters for job, country, dates, integration external id, hiring state, and stage type.

Returns: id, createdAt, lastUpdatedAt, attachments, source, job, candidate, screeningQuestions, consent, integrationExternalId, state, hiringState, pipelineStage, currentStage.

The deprecated state filter cannot be combined with hiringState or stageType; removed 2026-11-01. The stageType filter must be combined with hiringState.
- **get_single_join_application_by_id** — Get a single application in Join by id. Returns: id, createdAt, lastUpdatedAt, attachments, source, job, candidate, screeningQuestions, consent, integrationExternalId, state, hiringState, pipelineStage, currentStage. Required: id.
- **create_a_join_application** — Create an application in Join by adding a candidate to a job, with optional base64-encoded documents, source channel, and integration external id. Returns: id. Required: candidate (email, firstName, lastName) and jobId.
- **delete_a_join_application_by_id** — Delete an application in Join by id. Returns: message. Required: id.
- **join_applications_bulk_update_external_data** — Update an application's integration data with a new external id in Join. Returns: applicationId, integrationExternalId. Required: application_id, integrationExternalId.
- **join_applications_bulk_update** — Update the tags of an application in Join. Returns: message. Required: application_id and tags. This endpoint is deprecated.
- **list_all_join_candidates** — List Join candidates belonging to the authenticated company. Returns: id, firstName, lastName, email, phone, country, source, tags, professionalLinks, consent, applications, notes, createdAt. Supports fuzzy search by email or name, filtering by creation date, and embedding candidate notes.
- **get_single_join_candidate_by_id** — Get a single Join candidate by id. Returns the full candidate object: id, firstName, lastName, email, phone, country, source, tags, professionalLinks, consent, applications, notes, createdAt. Required: id.
- **update_a_join_candidate_by_id** — Update a Join candidate's tags by id. Returns the updated candidate object including its id. Required: id. The provided tags array replaces all of the candidate's current tags.
- **list_all_join_notes** — List all notes for a candidate in Join. Returns: id, userEmail, content, createdAt, lastUpdatedAt, isPrivate, replies. Required: candidate_id. Up to 50 notes per page.
- **create_a_join_note** — Create a note for a candidate in Join. Returns the created note including id, userEmail, content, createdAt, lastUpdatedAt, and isPrivate. Required: candidate_id and content.
- **update_a_join_note_by_id** — Update the content of a candidate note in Join. Returns the updated note including id, userEmail, content, createdAt, lastUpdatedAt, and isPrivate. Required: candidate_id, id, and content.
- **delete_a_join_note_by_id** — Delete a candidate note in Join. Returns a confirmation message (e.g. 'Note deleted'). Also deletes all replies of the note. Required: candidate_id and id.
- **list_all_join_offices** — List all offices in Join, optionally filtered by country code or city name (partial match). Returns: id, name, countryIso, city, streetName, streetNumber, postalCode, isDefault.
- **get_single_join_office_by_id** — Get a single office in Join by id. Returns: id, name, countryIso, city, streetName, streetNumber, postalCode, isDefault. Required: id.
- **create_a_join_office** — Create an office in Join. Returns: id. Required: city, countryIso. Only one office can be the default (isDefault) at a time.
- **update_a_join_office_by_id** — Update an office in Join by id. Returns: id. Required: id. All body fields are optional; streetName, streetNumber, and postalCode are nullable.
- **list_all_join_categories** — List all categories in Join, optionally translating the response via the language parameter (defaults to en). Returns each category with its id, slug, name, and subCategories (each with id, slug, and name). A job's category must be one of the sub-categories listed here.
- **list_all_join_employment_types** — List all employment types in Join. Returns: id, slug, name. An optional language parameter translates the response (defaults to en).
- **list_all_join_scorecards** — List all scorecards submitted for a specific application in Join. Returns each scorecard's id, submittedBy (with userId, firstName, lastName, email), overAllRecommendation, overAllImpression, dateOfSubmission, createdAt, updatedAt, attributes (name and rating), and questions (id, question, and answer). Required: application_id.
- **list_all_join_seniority_levels** — List all seniority levels in Join. Returns: id, slug, name.
- **join_attachments_download** — Download an application attachment from Join by id and external file name, using the sig signature JOIN puts in each attachment url (see applications.get). The response is the raw file (JOIN documents application/pdf), not JSON. Required: attachment_id, external_file_name, sig.
- **join_application_files_download** — Download an application file from Join by id and external file name, using the sig signature. The response is the raw file (JOIN documents application/pdf), not JSON. Required: application_file_id, external_file_name, sig.

## How it works

1. **Link your customer's JOIN account.** Use Truto's frontend SDK; we handle every OAuth and API key flow so you don't need to create the OAuth app.
2. **Authentication is automatic.** Truto refreshes tokens, stores credentials securely, and injects them into every API request.
3. **Call Truto's API to reach JOIN.** The Proxy API is a 1-to-1 mapping of the JOIN API.
4. **Get a unified response format.** Every response uses a single shape, with cursor-based pagination and data in the `result` field.

## Use cases

- **Offer JOIN as a native ATS integration in your sourcing tool** — Let your users push AI-sourced or externally-found candidates straight into their JOIN pipeline, so hiring managers never have to leave the ATS to review new applicants.
- **Automate assessment and background check workflows** — Trigger your assessment or screening product when a candidate hits a specific hiringState in JOIN, then write the results back as notes attached to the candidate's profile.
- **Hand off hired candidates to HRIS and onboarding platforms** — Detect candidates that reach the hired stage, pull their profile data and signed documents from JOIN, and auto-provision employee records without manual re-entry.
- **Build recruitment analytics and reporting dashboards** — Sync jobs, applications, candidates, and scorecard feedback from JOIN into your analytics product to give customers hiring funnel metrics, time-to-hire, and interviewer insights.
- **Power niche job board and distribution products** — Fetch active jobs from JOIN (with full salary, description, and contact payloads) to republish them on vertical-specific boards, then route applicants back into JOIN automatically.

## What you can build

- **Candidate push with persistent external IDs** — Create applications in JOIN with your own integrationExternalId so you can track candidates across both systems without duplicates.
- **Stage-change triggered workflows** — Poll applications by hiringState and stageType to kick off external actions like assessments, reference checks, or offer letter generation.
- **Two-way interview feedback sync** — Read native JOIN scorecards (questions, ratings, recommendations) into your product and write external feedback back as structured notes on the candidate.
- **Secure resume and attachment ingestion** — Download candidate CVs, offer letters, and application files from JOIN using the signed download endpoints, then store them in your platform's document system.
- **Job catalog sync with full content** — Mirror a customer's live JOIN job catalog — including salary, descriptions, offices, categories, and employment types — into your product for display or matching.
- **Bulk application lifecycle management** — Activate, archive, or bulk-change status on jobs and applications programmatically to keep JOIN pipelines in sync with actions taken in your product.

## FAQs

### How does authentication work for the JOIN integration?

Truto handles the full OAuth / API key handshake for JOIN on your behalf. Your end users connect their JOIN account through Truto's connect flow, and you receive a stable connection ID to call any of the available JOIN tools.

### Can I get complete job payloads including salary and descriptions?

Yes. JOIN's list_all_join_jobs endpoint only returns full job content (salary, descriptions, contacts, etc.) when called with the undocumented content=true parameter. Truto sets this by default, so you always receive the full payload.

### How should I filter applications by stage?

Use the hiringState parameter combined with stageType when listing applications. The legacy state filter is deprecated and scheduled for removal in November 2026, so new integrations should avoid it.

### How do I prevent duplicate candidates when pushing from my product?

When calling create_a_join_application, pass your own identifier as integrationExternalId. You can also backfill or correct this later using join_applications_bulk_update_external_data to maintain a persistent link between JOIN and your system.

### How do I download candidate resumes and offer letters?

Attachments aren't exposed as raw public URLs. Each application returns a signature (sig) and attachment identifier that must be passed into join_attachments_download or join_application_files_download to securely retrieve the raw file.

### How do I update tags on a candidate?

Tag updates at the application level are deprecated. Use update_a_join_candidate_by_id to override tags directly on the candidate record — this is the supported path going forward.

### Can I write interview feedback back into JOIN?

Yes. You can read native interviewer feedback via list_all_join_scorecards, and write external feedback (assessment scores, screening results, notes) onto a candidate using create_a_join_note and update_a_join_note_by_id.

## Related reading

- [Connect JOIN to Claude: Search Candidates and Analyze Scorecards](https://truto.one/blog/connect-join-to-claude-search-candidates-and-analyze-scorecards/) — Learn how to connect JOIN to Claude using an MCP server. Automate applicant tracking, extract resumes, and analyze interview scorecards with AI agents.
- [Connect JOIN to ChatGPT: Manage Job Postings and Applications](https://truto.one/blog/connect-join-to-chatgpt-manage-job-postings-and-applications/) — Learn how to connect JOIN to ChatGPT using a managed MCP server. Execute complex recruitment workflows, manage job postings, and automate candidate screening.
- [Connect JOIN to AI Agents: Automate the Full Recruitment Lifecycle](https://truto.one/blog/connect-join-to-ai-agents-automate-the-full-recruitment-lifecycle/) — Learn how to connect JOIN to AI agents using Truto's /tools endpoint. Step-by-step guide to automating candidate workflows and ATS operations.
