Skip to content

ATS · Beta

JOIN
API integration

Ship ATS features without building the integration. Full JOIN API access via Proxy and 30+ MCP-ready tools for AI agents — extend models and mappings to fit your product.

Built for specific customer use cases. Issues are resolved quickly.

Talk to us

Use Cases

Why integrate with JOIN

Common scenarios for SaaS companies building JOIN integrations for their customers.

01

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.

02

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.

03

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.

04

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.

05

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

Ship these features with Truto + JOIN

Concrete product features your team can ship faster by leveraging Truto’s JOIN integration instead of building from scratch.

01

Candidate push with persistent external IDs

Create applications in JOIN with your own integrationExternalId so you can track candidates across both systems without duplicates.

02

Stage-change triggered workflows

Poll applications by hiringState and stageType to kick off external actions like assessments, reference checks, or offer letter generation.

03

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.

04

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.

05

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.

06

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.

SuperAI

JOIN AI agent tools

Comprehensive AI agent toolset with fine-grained control. Integrates with MCP clients like Cursor and Claude, or frameworks like LangChain.

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.

Why Truto

Why use Truto’s MCP server for JOIN

Other MCP servers give you a static tool list for one app. Truto gives you a managed, multi-tenant MCP infrastructure across 850+ integrations.

01

Auto-generated, always up to date

Tools are dynamically generated from curated documentation — not hand-coded. As integrations evolve, tools stay current without manual maintenance.

02

Fine-grained access control

Scope each MCP server to read-only, write-only, specific methods, or tagged tool groups. Expose only what your AI agent needs — nothing more.

03

Multi-tenant by design

Each MCP server is scoped to a single connected account with its own credentials. The URL itself is the auth token — no shared secrets, no credential leaking across tenants.

04

Works with every MCP client

Standard JSON-RPC 2.0 protocol. Paste the URL into Claude, ChatGPT, Cursor, or any MCP-compatible agent framework — tools are discovered automatically.

05

Built-in auth, rate limits, and error handling

Tool calls execute through Truto’s proxy layer with automatic OAuth refresh, rate-limit handling, and normalized error responses. No raw API plumbing in your agent.

06

Expiring and auditable servers

Create time-limited MCP servers for contractors or automated workflows. Optional dual-auth requires both the URL and a Truto API token for high-security environments.

For your product

Ship JOIN tools in your product

Give the AI in your product access to each customer’s own JOIN account, with one MCP server per connected account.

Rather talk it through? Book a demo

Elaichi

For your own team

Use JOIN in ChatGPT or Claude yourself

Connect your company’s JOIN once, then ask in the AI you already use, with exactly your own access.

From the team behind Truto · 14-day free trial

How It Works

From zero to integrated

Go live with JOIN in under an hour. No boilerplate, no maintenance burden.

01

Link your customer’s JOIN account

Use Truto’s frontend SDK to connect your customer’s JOIN account. We handle all OAuth and API key flows — you don’t need to create the OAuth app.

02

We handle authentication

Don’t spend time refreshing access tokens or figuring out secure storage. We handle it and inject credentials into every API request.

03

Call our API, we call JOIN

Truto’s Proxy API is a 1-to-1 mapping of the JOIN API. You call us, we call JOIN, and pass the response back in the same cycle.

04

Unified response format

Every response follows a single format across all integrations. We translate JOIN’s pagination into unified cursor-based pagination. Data is always in the result attribute.

FAQs

Common questions about JOIN on Truto

Authentication, rate limits, data freshness, and everything else you need to know before you integrate.

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.

JOIN

Get JOIN integrated into your app

Our team understands what it takes to make a JOIN integration successful. A short, crisp 30 minute call with folks who understand the problem.