Entwickler
Die öffentliche API und die Webhooks: was sie abdecken, wie sie sich verhalten und was wir bei Änderungen zusagen.
OpenAPI-Dokument (JSON) · v0.537.0-beta
Authentifizierung
Jede Anfrage trägt einen API-Schlüssel als Bearer-Token: Authorization: Bearer <Schlüssel>. Ein Admin Ihrer Organisation legt Schlüssel unter Integrationen an, jeweils mit einer ausdrücklichen Liste von Berechtigungen und optionalem Ablaufdatum. Ein Schlüssel sieht nur die Daten der Organisation, zu der er gehört; ein abgelaufener oder widerrufener Schlüssel erhält 401, ein Schlüssel ohne die Berechtigung der Operation 403.
Limits
Jeder Schlüssel hat ein eigenes Fenster von 120 Anfragen pro Minute, Schreibzugriffe ein engeres von 30 pro Minute. Jede Antwort trägt RateLimit-Limit, RateLimit-Remaining und RateLimit-Reset; ein 429 zusätzlich Retry-After.
Sandbox-Schlüssel
Testen Sie die API mit synthetischen Daten: Ein Sandbox-Schlüssel liest jede Ressource der öffentlichen Demo, hat alle Leseberechtigungen und keine Schreibberechtigung, läuft nach 24 Stunden ab und erlaubt 1000 Anfragen pro Tag.
Sandbox-Schlüssel gibt es auf der öffentlichen Demo, die nur synthetische Daten enthält. Entwicklerseite der Demo öffnen
Konventionen
- Jede Liste antwortet mit { data, page: { nextCursor, hasMore } } und nimmt limit (Standard 50, höchstens 200), cursor und updatedSince. Die Reihenfolge ist aufsteigend nach letzter Änderung; ein Client dedupliziert über id.
- Schreibzugriffe akzeptieren einen Idempotency-Key-Header: derselbe Schlüssel mit demselben Body liefert die erste Antwort erneut, mit anderem Body ist es ein 409. Ein ungültiger Body erhält 422 mit einem Eintrag pro Feld.
- Jeder Fehler ist ein RFC-9457-Problem-Dokument (application/problem+json) mit stabilem type. Entscheiden Sie anhand von type, nie anhand von Titel oder Detailtext.
Endpunkte
| Methode | Pfad | Berechtigung | Was er tut |
|---|---|---|---|
| GET | /api/v1/candidates | candidates:read | List candidates (mentees) |
| POST | /api/v1/candidates | candidates:write | Create a candidate |
| GET | /api/v1/candidates/{id} | candidates:read | Get a candidate |
| PATCH | /api/v1/candidates/{id} | candidates:write | Update a candidate |
| PATCH | /api/v1/relationships/{id}/stage | relationships:write | Move a relationship’s pipeline stage |
| GET | /api/v1/me | — | Who am I (connector auth test) |
| GET | /api/v1/hooks | hooks:write | List this key’s subscriptions |
| POST | /api/v1/hooks | hooks:write | Subscribe (REST hook) |
| DELETE | /api/v1/hooks/{id} | hooks:write | Unsubscribe |
| POST | /api/v1/exports | — | Export a whole resource (asynchronous) |
| GET | /api/v1/exports/{id} | — | Get an export |
| POST | /api/v1/imports/candidates | candidates:write | Import candidates in bulk (queued) |
| GET | /api/v1/imports/{id} | candidates:write | Get an import and its report |
| GET | /api/v1/relationships | relationships:read | List relationships |
| GET | /api/v1/relationships/{id} | relationships:read | Get a relationship |
| GET | /api/v1/interactions | interactions:read | List interactions |
| POST | /api/v1/interactions | interactions:write | Log an interaction |
| GET | /api/v1/interactions/{id} | interactions:read | Get an interaction |
| GET | /api/v1/meetings | meetings:read | List meetings |
| GET | /api/v1/meetings/{id} | meetings:read | Get a meeting |
| GET | /api/v1/companies | companies:read | List companies |
| GET | /api/v1/companies/{id} | companies:read | Get a company |
| GET | /api/v1/requisitions | hiring:read | List requisitions |
| GET | /api/v1/requisitions/{id} | hiring:read | Get a requisition |
| GET | /api/v1/offers | hiring:read | List offers |
| GET | /api/v1/offers/{id} | hiring:read | Get an offer |
| GET | /api/v1/interview-requests | hiring:read | List interview requests |
| GET | /api/v1/interview-requests/{id} | hiring:read | Get an interview request |
Fehlertypen
| type | HTTP-Status |
|---|---|
| invalid_api_key | 401 |
| insufficient_scope | 403 |
| org_unbound | 403 |
| feature_locked | 403 |
| invalid_link | 403 |
| company_key_not_allowed | 403 |
| not_found | 404 |
| validation_failed | 400 / 422 |
| idempotency_key_reused | 409 |
| idempotency_in_progress | 409 |
| limit_reached | 409 |
| duplicate_candidate | 409 |
| invalid_transition | 409 |
| stage_conflict | 409 |
| rate_limited | 429 |
| quota_exceeded | 429 |
Webhooks
Ein Webhook ist ein POST von { event, data, sentAt } mit einem X-Signature-Header — dem hexadezimalen HMAC-SHA256 des exakten Request-Bodys unter dem Secret des Hooks — sowie X-Event und X-Delivery-Id. Prüfen Sie die Signatur am rohen Body, bevor Sie ihn parsen, und deduplizieren Sie über X-Delivery-Id: zugestellt wird mindestens einmal.
Eine Zustellung prüfen (Node.js)
const { createHmac, timingSafeEqual } = require('node:crypto');
// rawBody: the request body exactly as received (string or Buffer), before JSON.parse.
function verifyWebhook(secret, rawBody, signatureHeader) {
const expected = Buffer.from(createHmac('sha256', secret).update(rawBody).digest('hex'), 'hex');
const given = Buffer.from(String(signatureHeader || ''), 'hex');
return given.length === expected.length && timingSafeEqual(given, expected);
}Ereignisse
application.created@1
Schema von data
{
"version": 1,
"description": "Someone applied to a mentor through the public application form.",
"schema": {
"type": "object",
"properties": {
"mentorId": {
"type": "string",
"minLength": 1
},
"menteeName": {
"type": "string"
},
"email": {
"type": "string"
}
},
"required": [
"mentorId",
"menteeName",
"email"
],
"additionalProperties": false
}
}pipeline.stage_change@1
Schema von data
{
"version": 1,
"description": "A mentorship moved to another pipeline stage (`from` and `to` are stage keys).",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"from": {
"type": "string"
},
"to": {
"type": "string"
}
},
"required": [
"relationId",
"from",
"to"
],
"additionalProperties": false
}
}mentorship.created@1
Schema von data
{
"version": 1,
"description": "A mentor was assigned to a mentee.",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"mentorId": {
"type": "string",
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
},
"companyId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"relationId",
"mentorId",
"menteeId",
"companyId"
],
"additionalProperties": false
}
}interaction.logged@1
Schema von data
{
"version": 1,
"description": "An interaction (meeting, feedback, e-mail …) was logged on a mentorship.",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string"
},
"date": {
"type": "string",
"format": "date-time"
},
"autoLogged": {
"const": true
}
},
"required": [
"relationId",
"type",
"date"
],
"additionalProperties": false
}
}evaluation.added@1
Schema von data
{
"version": 1,
"description": "An evaluation was submitted for a mentorship.",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string"
},
"authorId": {
"type": "string",
"minLength": 1
}
},
"required": [
"relationId",
"type",
"authorId"
],
"additionalProperties": false
}
}meeting.scheduled@1
Schema von data
{
"version": 1,
"description": "One or more meetings were scheduled (a batch, an instant meeting or a series occurrence).",
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"scheduledAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"count": {
"type": "integer",
"minimum": 0
},
"instant": {
"const": true
},
"seriesId": {
"type": "string",
"minLength": 1
}
},
"required": [
"title",
"scheduledAt",
"count"
],
"additionalProperties": false
}
}meeting.rescheduled@1
Schema von data
{
"version": 1,
"description": "A meeting moved to another time.",
"schema": {
"type": "object",
"properties": {
"meetingId": {
"type": "string",
"minLength": 1
},
"scheduledAt": {
"type": "string",
"format": "date-time"
},
"previousScheduledAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"required": [
"meetingId",
"scheduledAt",
"previousScheduledAt"
],
"additionalProperties": false
}
}meeting.cancelled@1
Schema von data
{
"version": 1,
"description": "A meeting (or `count` meetings of one batch) was called off.",
"schema": {
"type": "object",
"properties": {
"meetingId": {
"type": "string",
"minLength": 1
},
"scheduledAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"count": {
"type": "integer",
"exclusiveMinimum": 0
}
},
"required": [
"meetingId",
"scheduledAt",
"count"
],
"additionalProperties": false
}
}interview_panel.completed@1
Schema von data
{
"version": 1,
"description": "Every interviewer on a panel has scored, or an admin closed it.",
"schema": {
"type": "object",
"properties": {
"panelId": {
"type": "string",
"minLength": 1
},
"subjectId": {
"type": "string",
"minLength": 1
}
},
"required": [
"panelId",
"subjectId"
],
"additionalProperties": false
}
}interview_panel.outcome@1
Schema von data
{
"version": 1,
"description": "A closed panel's decision was recorded.",
"schema": {
"type": "object",
"properties": {
"panelId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": "string",
"minLength": 1
},
"outcome": {
"type": "string",
"enum": [
"ADVANCE",
"REJECT",
"OFFER"
]
}
},
"required": [
"panelId",
"applicationId",
"outcome"
],
"additionalProperties": false
}
}interview_request.scheduled@1
Schema von data
{
"version": 1,
"description": "An approved interview request got a meeting.",
"schema": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"minLength": 1
},
"meetingId": {
"type": "string",
"minLength": 1
},
"scheduledAt": {
"type": "string",
"format": "date-time"
},
"panelId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"requestId",
"meetingId",
"scheduledAt",
"panelId"
],
"additionalProperties": false
}
}interview_request.cancelled@1
Schema von data
{
"version": 1,
"description": "An interview request was called off.",
"schema": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"minLength": 1
},
"meetingId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"requestId",
"meetingId"
],
"additionalProperties": false
}
}offer.accepted@1
Schema von data
{
"version": 1,
"description": "The candidate accepted an offer.",
"schema": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"offerId",
"applicationId",
"requisitionId"
],
"additionalProperties": false
}
}offer.declined@1
Schema von data
{
"version": 1,
"description": "The candidate declined an offer.",
"schema": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"offerId",
"applicationId",
"requisitionId"
],
"additionalProperties": false
}
}requisition.filled@1
Schema von data
{
"version": 1,
"description": "An acceptance took the last opening of a requisition.",
"schema": {
"type": "object",
"properties": {
"requisitionId": {
"type": "string",
"minLength": 1
},
"offerId": {
"type": "string",
"minLength": 1
}
},
"required": [
"requisitionId",
"offerId"
],
"additionalProperties": false
}
}mentorship.lifecycle_changed@1
Schema von data
{
"version": 1,
"description": "A mentorship was paused, resumed, ended or reopened (`from` and `to` are lifecycle states).",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"from": {
"type": "string"
},
"to": {
"type": "string"
},
"reasonCode": {
"type": [
"string",
"null"
]
}
},
"required": [
"relationId",
"from",
"to",
"reasonCode"
],
"additionalProperties": false
}
}application.stage_changed@1
Schema von data
{
"version": 1,
"description": "A candidate's application for a requisition moved to another stage (`from` and `to` are stage keys, e.g. SHORTLISTED → INTERVIEW).",
"schema": {
"type": "object",
"properties": {
"applicationId": {
"type": "string",
"minLength": 1
},
"requisitionId": {
"type": "string",
"minLength": 1
},
"from": {
"type": "string"
},
"to": {
"type": "string"
}
},
"required": [
"applicationId",
"requisitionId",
"from",
"to"
],
"additionalProperties": false
}
}mentorship.transferred@1
Schema von data
{
"version": 1,
"description": "A mentee's mentor changed — corrected in place, or a new pairing that carries the stage over.",
"schema": {
"type": "object",
"properties": {
"relationId": {
"type": "string",
"minLength": 1
},
"previousRelationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
},
"fromMentorId": {
"type": "string",
"minLength": 1
},
"toMentorId": {
"type": "string",
"minLength": 1
},
"mode": {
"type": "string",
"enum": [
"corrected",
"transferred"
]
},
"reasonCode": {
"type": "string"
}
},
"required": [
"relationId",
"previousRelationId",
"menteeId",
"fromMentorId",
"toMentorId",
"mode",
"reasonCode"
],
"additionalProperties": false
}
}offer.sent@1
Schema von data
{
"version": 1,
"description": "An offer was sent to the candidate.",
"schema": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"offerId",
"applicationId",
"requisitionId"
],
"additionalProperties": false
}
}offer.withdrawn@1
Schema von data
{
"version": 1,
"description": "A sent offer was withdrawn before the candidate decided.",
"schema": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"offerId",
"applicationId",
"requisitionId"
],
"additionalProperties": false
}
}offer.expired@1
Schema von data
{
"version": 1,
"description": "A sent offer passed its expiry date without a decision.",
"schema": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"minLength": 1
},
"applicationId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
}
},
"required": [
"offerId",
"applicationId",
"requisitionId"
],
"additionalProperties": false
}
}interview_request.created@1
Schema von data
{
"version": 1,
"description": "A company asked to interview a shortlisted candidate for a requisition.",
"schema": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"minLength": 1
},
"requisitionId": {
"type": "string",
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
},
"companyId": {
"type": "string",
"minLength": 1
}
},
"required": [
"requestId",
"requisitionId",
"menteeId",
"companyId"
],
"additionalProperties": false
}
}interview_request.approved@1
Schema von data
{
"version": 1,
"description": "The programme approved an interview request; scheduling comes next.",
"schema": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"minLength": 1
},
"requisitionId": {
"type": "string",
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
}
},
"required": [
"requestId",
"requisitionId",
"menteeId"
],
"additionalProperties": false
}
}interview_request.declined@1
Schema von data
{
"version": 1,
"description": "The programme declined an interview request (`reasonCode` is a decline code, never the note).",
"schema": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"minLength": 1
},
"requisitionId": {
"type": "string",
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
},
"reasonCode": {
"type": "string"
}
},
"required": [
"requestId",
"requisitionId",
"menteeId",
"reasonCode"
],
"additionalProperties": false
}
}company_interest.changed@1
Schema von data
{
"version": 1,
"description": "A company flagged a candidate as interesting, shortlisted or passed (`from` and `to` are interest states).",
"schema": {
"type": "object",
"properties": {
"interestId": {
"type": "string",
"minLength": 1
},
"companyId": {
"type": "string",
"minLength": 1
},
"menteeId": {
"type": "string",
"minLength": 1
},
"requisitionId": {
"type": [
"string",
"null"
],
"minLength": 1
},
"from": {
"type": [
"string",
"null"
]
},
"to": {
"type": "string"
}
},
"required": [
"interestId",
"companyId",
"menteeId",
"requisitionId",
"from",
"to"
],
"additionalProperties": false
}
}Versionierung und Deprecation
Innerhalb von v1 sind Änderungen nur additiv: neue Endpunkte, neue optionale Parameter, neue Felder und neue Fehlertypen können jederzeit hinzukommen; ignorieren Sie, was Sie nicht kennen. Ein Feld, einen Parameter oder Endpunkt zu entfernen oder umzubenennen, einen Typ zu ändern oder die Validierung zu verschärfen, ist inkompatibel: Das wird mindestens 6 Monate vorher angekündigt und unten aufgeführt, und eine abgekündigte Operation antwortet mit Deprecation- und Sunset-Headern. Eine Änderung, die diese Zusage nicht halten kann, kommt als optionaler Parameter innerhalb von v1 oder als v2.
Angekündigte Abkündigungen
| Was | Seit | Entfernt am |
|---|---|---|
| `candidates` key on `GET /api/v1/candidates` (alias of `data`) | #1988 | 2027-01-31 |
Jede ausgelieferte Änderung, die API eingeschlossen, steht datiert in den Versionshinweisen. Versionshinweise