Integrations

Custom ATS Integration

Build a custom API so Wintro can sync jobs and referrals with your Applicant Tracking System.

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.

How it works

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.

Getting started

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.


What Wintro syncs

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.

Referrals

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”).

Referral progress

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.

Pipeline mapping

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 state What it means Example stages in your ATS
Entry Where new referrals land “New Referral”, “Applied”
Interview Actively being evaluated “Phone Screen”, “Onsite”, “Reference Check”
Exclusion Removed from consideration (not final) “Not Qualified”, “No Show”
Rejection Final “no” “Rejected”, “Declined”
Hired Final “yes” “Offer Accepted”, “Hired”

:::tip If your ATS already provides an outcome field on applications (e.g. PENDING, HIRED, REJECTED), Wintro can use that directly, you only need to map entry and exclusion stages. :::


API specification

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.

Overview

Endpoint Method Purpose Called
Get jobs GET All open positions with stages Hourly
Get candidates for a job GET Candidates in a specific job pipeline Hourly
Get candidates by ID GET Bulk status lookup for tracked referrals Hourly
Create application POST Submit a new referral On referral
Add note POST Attach referral context On referral
Add tag POST Tag as “Wintro Referral” On referral
Get stages GET List all pipeline stages On setup

1. Get jobs

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 }
    ]
  }
]
Field Type Required Description
id string Yes Unique job identifier
title string Yes Job title
status string Yes open, closed, or archived
location string No Job location
department string No Department name
description string No Job description (HTML or plain text)
updated_at ISO 8601 Yes Last modification timestamp
stages array Yes Ordered pipeline stages (see below)

Each stage object:

Field Type Required Description
id string Yes Unique stage identifier
name string Yes Human-readable stage name
index number Yes Position in the pipeline (1 = first)
Wintro uses updated_at for incremental syncing, only jobs that changed since the last sync are updated. Make sure this timestamp reflects any changes to the job posting, status, or stages.

2. Get candidates for a job

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"
  }
]
Field Type Required Description
id string Yes Unique candidate identifier
first_name string Yes Candidate first name
last_name string Yes Candidate last name
application_id string Yes Application identifier
current_stage_id string Yes Current pipeline stage ID
outcome string | null Yes PENDING, HIRED, or DECLINED
changed_at ISO 8601 Yes Last status change timestamp

3. Get candidates by ID

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.

This endpoint must support comma-separated IDs for bulk fetching.

4. Create application

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"
}
Field Type Required Description
first_name string Yes Candidate first name
last_name string Yes Candidate last name
email string Yes Candidate email
phone string No Candidate phone number
resume_url string No URL to download the resume/CV
stage_id string No Initial 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.


5. Add note (optional)

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"
}

6. Add tag (optional)

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"
}

7. Get stages

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 }
]
Field Type Required Description
id string Yes Unique stage identifier
name string Yes Human-readable stage name
index number Yes Position in the pipeline (1 = first)

Authentication

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.

Rate limiting

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.

Error handling

Return standard HTTP status codes:

Status Meaning
200 Success
400 Invalid input
401 Invalid or expired credentials
404 Resource not found (e.g. job was closed)
429 Rate limit exceeded
500 Server 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.


Questions?

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