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.
How it works
Section titled “How it works”Wintro calls your API — you never need to call ours. Once connected, the sync runs automatically:
- Wintro pulls your open jobs every hour so employees can refer candidates.
- When an employee submits a referral, Wintro pushes the candidate into your ATS pipeline.
- 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
Section titled “Getting started”To set up the integration, share the following with your Wintro contact:
- Base URL — Where your API is hosted (e.g.
https://ats.yourcompany.com). - Authentication credentials — An API key or OAuth 2.0 client credentials (see Authentication).
- Rate limits — Any request limits Wintro should respect (see Rate limiting).
- 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
Section titled “What Wintro syncs”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
Section titled “Referrals”When an employee submits a referral through Wintro:
- Wintro creates an application in your ATS for the referred candidate.
- Attaches a note with referral context (who referred them, why they’re a fit).
- Tags the candidate as a “Wintro Referral” for easy filtering.
- Places the candidate in your configured entry stage (e.g. “New Referral”).
Referral progress
Section titled “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
Section titled “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” |
API specification
Section titled “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
Section titled “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
Section titled “1. Get jobs”GET /api/jobsReturns 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) |
2. Get candidates for a job
Section titled “2. Get candidates for a job”GET /api/jobs/{jobId}/candidatesReturns 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
Section titled “3. Get candidates by ID”GET /api/candidates?ids=candidate-456,candidate-789Bulk 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.
4. Create application
Section titled “4. Create application”POST /api/jobs/{jobId}/applicationsCalled 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)
Section titled “5. Add note (optional)”POST /api/applications/{applicationId}/notesAdds 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)
Section titled “6. Add tag (optional)”POST /api/candidates/{candidateId}/tagsTags 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
Section titled “7. Get stages”GET /api/stagesReturns 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
Section titled “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
Section titled “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
Section titled “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?
Section titled “Questions?”Reach out to your Wintro contact to discuss your integration. We’re happy to help review your API design before you start building.