Skip to content

Custom ATS Integration

If your ATS is not in our list of supported integrations, you can build a simple REST API that Wintro will call to keep your jobs and referrals in sync. This guide describes exactly what your API needs to look like.

Wintro calls your API — you never need to call ours. Once connected, the sync runs automatically:

  1. Wintro pulls your open jobs every hour so employees can refer candidates.
  2. When an employee submits a referral, Wintro pushes the candidate into your ATS pipeline.
  3. Wintro tracks each referral’s progress by polling your API hourly, and notifies the referring employee when their candidate advances.

Your API just needs to respond to a handful of endpoints — Wintro handles scheduling, retries, and error recovery.

To set up the integration, share the following with your Wintro contact:

  1. Base URL — Where your API is hosted (e.g. https://ats.yourcompany.com).
  2. Authentication credentials — An API key or OAuth 2.0 client credentials (see Authentication).
  3. Rate limits — Any request limits Wintro should respect (see Rate limiting).
  4. Stage mapping — Which of your pipeline stages correspond to Wintro’s states (see Pipeline mapping).

Wintro will configure the connection on our side and run an initial sync to pull in your open jobs.


Wintro pulls all open positions from your ATS every hour. Each job appears on the Wintro platform where employees can browse and make referrals. When a job is closed or archived in your ATS, Wintro automatically removes it.

When an employee submits a referral through Wintro:

  1. Wintro creates an application in your ATS for the referred candidate.
  2. Attaches a note with referral context (who referred them, why they’re a fit).
  3. Tags the candidate as a “Wintro Referral” for easy filtering.
  4. Places the candidate in your configured entry stage (e.g. “New Referral”).

Once a referral is created, Wintro checks your API hourly for status changes:

  • Detects stage transitions (e.g. Applied → Phone Screen → Interview → Offer).
  • Updates the referral status in Wintro accordingly.
  • Notifies the referring employee when their candidate advances, gets hired, or is rejected.

During setup, you’ll map your ATS pipeline stages to Wintro’s internal states. This tells Wintro how to interpret your candidate’s journey:

Wintro stateWhat it meansExample stages in your ATS
EntryWhere new referrals land”New Referral”, “Applied”
InterviewActively being evaluated”Phone Screen”, “Onsite”, “Reference Check”
ExclusionRemoved from consideration (not final)“Not Qualified”, “No Show”
RejectionFinal “no""Rejected”, “Declined”
HiredFinal “yes""Offer Accepted”, “Hired”

Below are the endpoints your API needs to expose. The URL paths are suggestions — as long as the request/response formats match, the exact paths can differ.

EndpointMethodPurposeCalled
Get jobsGETAll open positions with stagesHourly
Get candidates for a jobGETCandidates in a specific job pipelineHourly
Get candidates by IDGETBulk status lookup for tracked referralsHourly
Create applicationPOSTSubmit a new referralOn referral
Add notePOSTAttach referral contextOn referral
Add tagPOSTTag as “Wintro Referral”On referral
Get stagesGETList all pipeline stagesOn setup

GET /api/jobs

Returns all open positions. Wintro calls this hourly to sync your job listings.

Response:

[
{
"id": "job-123",
"title": "Senior Software Engineer",
"status": "open",
"location": "Brussels, Belgium",
"department": "Engineering",
"description": "<p>We're looking for...</p>",
"updated_at": "2025-03-01T12:00:00Z",
"stages": [
{ "id": "stage-1", "name": "Applied", "index": 1 },
{ "id": "stage-2", "name": "Phone Screen", "index": 2 },
{ "id": "stage-3", "name": "Interview", "index": 3 },
{ "id": "stage-4", "name": "Offer", "index": 4 }
]
}
]
FieldTypeRequiredDescription
idstringYesUnique job identifier
titlestringYesJob title
statusstringYesopen, closed, or archived
locationstringNoJob location
departmentstringNoDepartment name
descriptionstringNoJob description (HTML or plain text)
updated_atISO 8601YesLast modification timestamp
stagesarrayYesOrdered pipeline stages (see below)

Each stage object:

FieldTypeRequiredDescription
idstringYesUnique stage identifier
namestringYesHuman-readable stage name
indexnumberYesPosition in the pipeline (1 = first)

GET /api/jobs/{jobId}/candidates

Returns all candidates in a specific job’s pipeline. Wintro calls this hourly per job to identify existing candidates and avoid suggesting duplicates.

Response:

[
{
"id": "candidate-456",
"first_name": "John",
"last_name": "Doe",
"application_id": "app-789",
"current_stage_id": "stage-2",
"outcome": null,
"changed_at": "2025-03-01T14:30:00Z"
}
]
FieldTypeRequiredDescription
idstringYesUnique candidate identifier
first_namestringYesCandidate first name
last_namestringYesCandidate last name
application_idstringYesApplication identifier
current_stage_idstringYesCurrent pipeline stage ID
outcomestring | nullYesPENDING, HIRED, or DECLINED
changed_atISO 8601YesLast status change timestamp

GET /api/candidates?ids=candidate-456,candidate-789

Bulk lookup of specific candidates by their IDs. Wintro calls this hourly to track the progress of referred candidates through your pipeline.

Response: Same format as Get candidates for a job.


POST /api/jobs/{jobId}/applications

Called when an employee submits a referral through Wintro. Creates a new candidate and application in your ATS.

Request body:

{
"first_name": "Jane",
"last_name": "Smith",
"email": "jane.smith@example.com",
"phone": "+32 470 12 34 56",
"resume_url": "https://storage.wintro.ai/cv/abc123.pdf",
"stage_id": "stage-1"
}
FieldTypeRequiredDescription
first_namestringYesCandidate first name
last_namestringYesCandidate last name
emailstringYesCandidate email
phonestringNoCandidate phone number
resume_urlstringNoURL to download the resume/CV
stage_idstringNoInitial pipeline stage to place the candidate in

Response:

{
"candidate_id": "candidate-456",
"application_id": "app-789"
}

Wintro needs both IDs to track the referral through your pipeline going forward.


POST /api/applications/{applicationId}/notes

Adds referral context to the candidate’s application. If your Create application endpoint supports a note field, this can be skipped.

Request body:

{
"content": "Wintro referral - Senior Software Engineer\n\nCandidate: John Doe\nReferrer: Jane Smith\nKnow how: Worked together at previous company for 3 years\nWhy fit: Has exact skills needed for this role, culture fit"
}

POST /api/candidates/{candidateId}/tags

Tags the candidate as a Wintro referral for easy filtering in your ATS. If your Create application endpoint supports a tags field, this can be skipped.

Request body:

{
"tag": "Wintro Referral"
}

GET /api/stages

Returns all available pipeline stages. Wintro calls this during initial setup so your team can map stages to Wintro states.

Response:

[
{ "id": "stage-1", "name": "Applied", "index": 1 },
{ "id": "stage-2", "name": "Phone Screen", "index": 2 },
{ "id": "stage-3", "name": "Interview", "index": 3 },
{ "id": "stage-4", "name": "Offer", "index": 4 },
{ "id": "stage-5", "name": "Hired", "index": 5 }
]
FieldTypeRequiredDescription
idstringYesUnique stage identifier
namestringYesHuman-readable stage name
indexnumberYesPosition in the pipeline (1 = first)

All endpoints must be secured with one of:

  • API Key — Send via Authorization: Bearer {api_key} header (simplest option).
  • OAuth 2.0 — Client credentials flow (recommended for production environments).

Share your chosen method and credentials with your Wintro contact during setup. Wintro stores all credentials encrypted.

If your API has rate limits, let us know:

  • Maximum requests per minute or hour.
  • Any per-endpoint limits.
  • Recommended batch sizes for bulk operations.

Wintro has built-in rate limiting and will adapt to your constraints.

Return standard HTTP status codes:

StatusMeaning
200Success
400Invalid input
401Invalid or expired credentials
404Resource not found (e.g. job was closed)
429Rate limit exceeded
500Server error

For errors, return a JSON body so we can diagnose issues quickly:

{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests, retry after 60 seconds"
}
}

Wintro automatically retries on transient errors (429, 5xx) with exponential backoff.


Reach out to your Wintro contact to discuss your integration. We’re happy to help review your API design before you start building.