Aller au contenu principal
Intégration ATS

Alimentez votre ATS existant en candidats vérifiés

InTransparency ne remplace pas votre ATS : il l'alimente. Lorsqu'une correspondance à haut niveau de confiance se déclenche, nous envoyons un webhook signé ; un relais de 30 lignes le transforme en prospect Greenhouse, en opportunité Lever ou en candidat de réquisition Workday.

Le principe

InTransparency déclenche un webhook → votre petit relais vérifie la signature → votre relais appelle l'endpoint candidates de votre ATS. Aucun middleware personnalisé, aucun polling, aucune synchronisation planifiée. Le relais s'exécute n'importe où (Vercel, Cloudflare Workers, AWS Lambda ou un conteneur FastAPI).

1. Créez une clé d'agent et enregistrez un webhook

# Step 1: Create an InTransparency agent key with webhook scope
curl -X POST https://www.in-transparency.com/api/agents/keys \
  -H "Cookie: <your session>" \
  -H "Content-Type: application/json" \
  -d '{"name":"ATS-relay","scopes":["agent:webhook"]}'
# Response: { "key": "ita_...", ... } — save it once; never shown again

# Step 2: Register your webhook endpoint with InTransparency
curl -X POST https://www.in-transparency.com/api/agents/webhooks \
  -H "Authorization: Bearer ita_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-relay.example.com/webhooks/intransparency",
    "events": ["match.created", "credential.issued"]
  }'
# Response includes { "secret": "..." } — store as INTRANSPARENCY_WEBHOOK_SECRET

2. Relais Greenhouse (Node / TypeScript)

Greenhouse Harvest API

// Deno / Node webhook relay: InTransparency → Greenhouse Harvest API
// Env: GREENHOUSE_API_KEY, INTRANSPARENCY_WEBHOOK_SECRET, GREENHOUSE_JOB_ID
import crypto from 'node:crypto'

export default async function relay(req: Request): Promise<Response> {
  // 1. Verify the signature
  const body = await req.text()
  const sig = req.headers.get('X-InTransparency-Signature') || ''
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.INTRANSPARENCY_WEBHOOK_SECRET!)
    .update(body).digest('hex')
  if (sig !== expected) return new Response('bad signature', { status: 401 })

  const { event, data } = JSON.parse(body)
  if (event !== 'match.created' || data.matchScore < 70) {
    return new Response('ignored', { status: 200 })
  }

  // 2. Fetch the candidate's full profile from InTransparency
  const candidate = await fetch(
    'https://www.in-transparency.com/api/agents/companies/' + data.candidateSlug,
  ).then(r => r.json())

  // 3. Create a prospect in Greenhouse — the "Prospects" stage is perfect
  // for sourced leads; they convert to candidates once a recruiter adds them
  // to a job.
  await fetch('https://harvest.greenhouse.io/v1/candidates', {
    method: 'POST',
    headers: {
      'Authorization': 'Basic ' + Buffer.from(process.env.GREENHOUSE_API_KEY + ':').toString('base64'),
      'Content-Type': 'application/json',
      'On-Behalf-Of': process.env.GREENHOUSE_USER_ID!,
    },
    body: JSON.stringify({
      first_name: data.candidateName.split(' ')[0],
      last_name: data.candidateName.split(' ').slice(1).join(' '),
      email_addresses: [{ value: candidate.email, type: 'personal' }],
      applications: [{ job_id: Number(process.env.GREENHOUSE_JOB_ID) }],
      attachments: [{
        filename: 'intransparency-evidence.pdf',
        type: 'other',
        url: 'https://www.in-transparency.com/en/matches/' + data.matchId + '/why',
      }],
      custom_fields: {
        intransparency_match_score: data.matchScore,
        intransparency_match_id: data.matchId,
      },
    }),
  })

  return new Response('ok', { status: 200 })
}

3. Relais Lever (Python / FastAPI)

Lever Opportunities API

# Python / FastAPI webhook relay: InTransparency → Lever API
# Env: LEVER_API_KEY, INTRANSPARENCY_WEBHOOK_SECRET, LEVER_POSTING_ID
import hashlib, hmac, os, json, httpx
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

@app.post("/webhooks/intransparency")
async def relay(req: Request):
    body = await req.body()
    sig = req.headers.get("X-InTransparency-Signature", "")
    expected = "sha256=" + hmac.new(
        os.environ["INTRANSPARENCY_WEBHOOK_SECRET"].encode(),
        body, hashlib.sha256,
    ).hexdigest()
    if not hmac.compare_digest(sig, expected):
        raise HTTPException(401, "bad signature")

    payload = json.loads(body)
    if payload["event"] != "match.created": return {"ok": True}
    data = payload["data"]
    if data["matchScore"] < 70: return {"ok": True}

    # Lever: create an opportunity (candidate attached to a posting)
    async with httpx.AsyncClient(auth=(os.environ["LEVER_API_KEY"], "")) as client:
        r = await client.post(
            "https://api.lever.co/v1/opportunities",
            json={
                "name": data["candidateName"],
                "origin": "sourced",
                "sources": ["InTransparency"],
                "postings": [os.environ["LEVER_POSTING_ID"]],
                "tags": [f"intransparency-score-{data['matchScore']}"],
                "links": [data["url"]],
            },
        )
        r.raise_for_status()
    return {"ok": True}

Autres plateformes ATS

Workday Recruiting

Utilisez le Recruiting Staffing Web Service (SOAP) : ajoutez un Candidate avec l'opération Add_Candidate. Même principe de relais, payload différent.

SmartRecruiters

Faites un POST vers /candidates avec jobId et status=LEAD. Les champs personnalisés se mappent proprement.

Recruitee

Faites un POST vers /candidates avec placements=[{offer_id}]. Joignez l'URL de preuve en tant que note.

Teamtailor

Faites un POST vers /v1/candidates avec les job-applications incluses. Les candidats sourcés apparaissent dans le pipeline en tant que leads.

Personio

Utilisez la Recruiting API : POST /v1/recruiting/applications. Les équipes RH italiennes déjà familières avec Personio peuvent mettre cela en place en moins d'une heure.

Ashby

Faites un POST vers /candidate.create, puis vers /candidate.addApplication. Leur API est nativement compatible avec les webhooks, d'où une logique de relais minimale.