API-Referenz
Authentifizieren Sie sich und fragen Sie die Hiring-API nach Stellenanzeigen, Kandidaten und Bewerbungen ab.
Warum das zählt
Die Hiring-API gibt externen Systemen Lesezugriff auf Ihre Hiring-Daten — Jobbörsen rufen veröffentlichte Stellenanzeigen ab, HRIS-Systeme synchronisieren Kandidatendatensätze, Dashboards verfolgen Pipeline-Metriken. Token-Scopes stellen sicher, dass jede Integration nur das sieht, was sie benötigt.
Basis-URL
Alle API-Endpunkte sind erreichbar über:
https://startupkit.app/api/v1
Authentifizierung
Jede Anfrage erfordert ein API-Token im Authorization-Header:
Authorization: Bearer YOUR_TOKEN
Alternatives Format (beide funktionieren):
Authorization: token YOUR_TOKEN
Erstellen Sie Tokens unter Einstellungen > API. Jedes Token muss explizite Scopes haben, um auf Hiring-Endpunkte zugreifen zu können.
| Scope | Zugriff |
|---|---|
job_postings:read |
Stellenanzeigen und Phasen |
candidates:read |
Personenbezogene Kandidatendaten (Name, E-Mail, Telefon), Metafelder von Bewerbungen, Lebenslauf-Downloads |
applications:read |
Bewerbungen, Phasenverlauf, Lebenslauf-Downloads |
Tokens ohne Scopes können nicht auf Hiring-Endpunkte zugreifen.
Token-Format und Lebenszyklus
-
Format: 24-stelliger base58-String (z. B.
k3Jf9pQ2mZ7xR4nL8vT6bWyH) - Wird nur einmal angezeigt: Das Roh-Token wird genau einmal angezeigt — auf dem Bestätigungsbildschirm direkt nach dem Erstellen. Kopieren Sie es dann; es lässt sich später nicht erneut abrufen.
- Nur Digest-Speicherung: Kit speichert ausschließlich einen SHA-256-Digest des Tokens, niemals den Klartext. Wenn Sie das Token verlieren, widerrufen Sie es und erstellen Sie ein neues — der ursprüngliche Wert lässt sich nicht wiederherstellen.
-
Nachverfolgung der letzten Nutzung: Jede erfolgreiche Anfrage aktualisiert
last_used_at - Kein Ablaufdatum: Tokens laufen nicht nach einer festen Frist ab. Das Erstellungsformular bietet keine Ablaufoption, und unter Einstellungen > API wird kein Ablaufdatum angezeigt — ein Token bleibt gültig, bis es widerrufen wird.
- Inaktivitätswarnungen: Tokens, die länger als 30 Tage nicht verwendet wurden, lösen Admin-Benachrichtigungen aus
- Automatischer Widerruf: Tokens werden automatisch widerrufen, wenn ein Benutzer aus dem Konto entfernt wird
Best Practice: Erstellen Sie separate Tokens pro Integration mit den minimal erforderlichen Scopes.
Kontozuordnung
Jedes API-Token ist an ein bestimmtes Konto gebunden. Das Konto wird automatisch aus dem Token abgeleitet — es ist kein account_id-Parameter erforderlich.
Wenn ein Teammitglied aus einem Konto entfernt wird, werden dessen Tokens für dieses Konto automatisch widerrufen.
Fehlerantworten
| Status | Bedeutung | Häufige Ursachen |
|---|---|---|
400 |
Fehlerhafte Anfrage | Kontokontext fehlt (Sonderfall bei sitzungsbasierter Authentifizierung) |
401 |
Nicht autorisiert | Fehlendes, ungültiges oder widerrufenes Token |
403 |
Verboten | Token hat nicht den erforderlichen Scope für diesen Endpunkt |
404 |
Nicht gefunden | Ressource existiert nicht oder gehört nicht zu Ihrem Konto |
422 |
Nicht verarbeitbar | Validierungsfehler (hauptsächlich für Nicht-Hiring-Endpunkte) |
Paginierung
Listen-Endpunkte geben paginierte Ergebnisse zurück:
{
"data": [...],
"pagination": {
"current_page": 1,
"total_pages": 3,
"total_count": 42,
"per_page": 20
}
}
Übergeben Sie ?page=2, um nachfolgende Seiten abzurufen.
Stellenanzeigen
Erforderlicher Scope: job_postings:read
Stellenanzeigen auflisten
GET /api/v1/job_postings
Beispiel:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://startupkit.app/api/v1/job_postings?status=published
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
status |
string | Filtern nach draft, published, paused oder closed
|
page |
integer | Seitennummer |
Antwort:
{
"data": [
{
"id": "job_abc123",
"title": "Senior Rails Developer",
"status": "published",
"department": "Engineering",
"location": "New York, NY",
"employment_type": "full_time",
"remote": true,
"salary_min": "120000.0",
"salary_max": "180000.0",
"salary_currency": "USD",
"salary_period": "year",
"published_at": "2026-01-15T10:00:00Z",
"closed_at": null,
"created_at": "2026-01-10T08:30:00Z",
"updated_at": "2026-02-01T14:20:00Z",
"stages": [
{
"id": "stg_def456",
"name": "Screening",
"stage_type": "default",
"position": 0
}
],
"counts": {
"total_applications": 24,
"active_applications": 18,
"rejected": 6
}
}
],
"pagination": { ... }
}
Stellenanzeige abrufen
GET /api/v1/job_postings/:id
Gibt die gleiche Struktur wie ein Element in der Listenantwort zurück.
Phasen auflisten
GET /api/v1/job_postings/:job_posting_id/stages
Antwort:
{
"data": [
{
"id": "stg_def456",
"name": "Screening",
"stage_type": "default",
"position": 0
}
]
}
Phasen sind nach Position sortiert. Keine Paginierung.
Kandidaten
Erforderlicher Scope: candidates:read
Kandidaten auflisten
GET /api/v1/candidates
Beispiel:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://startupkit.app/api/v1/[email protected]
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
search |
string | Suche nach Name oder E-Mail |
page |
integer | Seitennummer |
Antwort:
{
"data": [
{
"id": "cand_ghi789",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone": "+1-555-0100",
"status": "active",
"github_username": "johndoe",
"created_at": "2026-01-20T09:15:00Z",
"applications": [
{
"id": "app_jkl012",
"job_posting_id": "job_abc123",
"job_posting_title": "Senior Rails Developer",
"current_stage_name": "Interview",
"status": "active",
"submitted_at": "2026-01-20T09:15:00Z"
}
]
}
],
"pagination": { ... }
}
Kandidat abrufen
GET /api/v1/candidates/:id
Gibt die gleiche Struktur wie ein Element in der Listenantwort zurück.
Bewerbungen
Erforderlicher Scope: applications:read
Bewerbungen auflisten
GET /api/v1/applications
Beispiel:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://startupkit.app/api/v1/applications?job_posting_id=job_abc123&status=active
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
job_posting_id |
string | Filtern nach Stellenanzeigen-Präfix-ID |
status |
string | Filtern nach active oder rejected
|
page |
integer | Seitennummer |
Antwort:
{
"data": [
{
"id": "app_jkl012",
"job_posting_id": "job_abc123",
"candidate_id": "cand_ghi789",
"current_stage_name": "Interview",
"status": "active",
"submitted_at": "2026-01-20T09:15:00Z",
"created_at": "2026-01-20T09:15:00Z",
"updated_at": "2026-02-10T11:30:00Z",
"candidate": {
"id": "cand_ghi789",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]"
},
"stage_history": [
{
"id": "sp_mno345",
"stage_name": "Screening",
"stage_type": "default",
"status": "completed",
"started_at": "2026-01-20T09:15:00Z",
"completed_at": "2026-01-25T16:00:00Z"
},
{
"id": "sp_pqr678",
"stage_name": "Interview",
"stage_type": "interview",
"status": "in_progress",
"started_at": "2026-01-25T16:00:00Z",
"completed_at": null
}
],
"metafields": [
{
"key": "years_of_experience",
"label": "Years of Experience",
"field_type": "number",
"value": "8",
"source": "ai",
"confidence": 0.92,
"extracted_at": "2026-01-20T09:18:00Z",
"edited": false,
"original_value": null
},
{
"key": "salary_expectation",
"label": "Salary Expectation",
"field_type": "number",
"value": "150000",
"source": "ai",
"confidence": 0.75,
"extracted_at": "2026-01-20T09:18:00Z",
"edited": true,
"original_value": "140000"
}
]
}
],
"pagination": { ... }
}
Metafeld-Daten
Erforderlicher Scope: candidates:read
Metafeld-Werte enthalten von der KI extrahierte personenbezogene Kandidatendaten. Deshalb ist das metafields-Array an den Scope candidates:read gebunden — denselben Scope, der auch den candidate-Block absichert — und nicht an applications:read. Ein Token mit applications:read, aber ohne candidates:read, erhält Bewerbungsantworten ganz ohne den Schlüssel metafields. Die obige Beispielantwort zeigt, was ein Token mit beiden Scopes sieht.
Besitzt das Token candidates:read, enthält jede Bewerbung ein metafields-Array mit strukturierten Datenfeldern, die für diese Bewerbung extrahiert oder eingegeben wurden. Jeder Eintrag hat:
| Feld | Typ | Beschreibung |
|---|---|---|
key |
string | Maschinenlesbarer Bezeichner für das Feld |
label |
string | Menschenlesbarer Anzeigename |
field_type |
string | Datentyp – genau einer dieser neun: text, textarea, number, date, select, boolean, url, rating, tags
|
value |
string | null | Aktueller Wert (immer als String serialisiert) |
source |
string | Wie der Wert gesetzt wurde – genau einer von zwei Werten: manual (von einer Person eingegeben oder bearbeitet) oder ai (von der KI extrahiert oder gesetzt) |
confidence |
float | null | KI-Konfidenzwert (0.0–1.0), wenn source gleich ai ist; andernfalls null
|
extracted_at |
timestamp | null | Wann der Wert gesetzt oder extrahiert wurde |
edited |
boolean |
true nur dann, wenn ein KI-generierter Wert später durch etwas anderes als die ursprüngliche KI-Extraktion überschrieben wurde (in der Praxis durch einen MCP-Aufruf hiring_update_metafield_value). Änderungen, die eine Person in Kits eigener Oberfläche vornimmt, speichern source: manual und melden stets edited: false. |
original_value |
string | null | Der ursprüngliche KI-extrahierte Wert vor manuellen Änderungen; null, falls nie bearbeitet |
Innerhalb eines Tokens mit candidates:read wird das metafields-Array nicht zusätzlich anhand des Sichtbarkeits-Flags managers_only gefiltert. Jedes für die Stellenanzeige definierte Metafeld – einschließlich der in der Konfiguration der Stellenanzeige als managers_only markierten Felder – wird zurückgegeben, unabhängig von der Rolle des Token-Inhabers. candidates:read ist damit die einzige Kontrolle über die Offenlegung von Metafeldern: Wenn ein Feld vertrauliche Informationen enthält, die Sie nicht gegenüber einer Integration offenlegen möchten, erteilen Sie dieser Integration nicht den Scope candidates:read, da die API die an anderer Stelle in der App verwendete Sichtbarkeitsfilterung für Manager nicht anwendet. applications:read allein zu vergeben, ist in dieser Hinsicht unbedenklich – der Scope liefert Phasenverlauf und Bewerbungsstatus ohne Metafelder.
Bewerbung abrufen
GET /api/v1/applications/:id
Gibt die gleiche Struktur wie ein Element in der Listenantwort zurück. Wenn das Token den Scope candidates:read besitzt und der Bewerbung ein Lebenslauf beigefügt ist, enthält die Antwort Lebenslauf-Metadaten:
{
"id": "app_jkl012",
"resume_filename": "john_doe_resume.pdf",
"resume_content_type": "application/pdf",
"resume_byte_size": 245760,
...
}
Diese Felder werden ausgelassen, wenn kein Lebenslauf angehängt ist oder der Scope candidates:read fehlt.
Lebenslauf herunterladen
Erforderliche Scopes: applications:read + candidates:read
GET /api/v1/applications/:application_id/resume
Lädt den Lebenslauf des Kandidaten für die angegebene Bewerbung herunter. Gibt eine 302-Weiterleitung zu einer zeitlich begrenzten signierten URL zurück (gültig für 30 Minuten).
Beispiel:
curl -L -H "Authorization: Bearer YOUR_TOKEN" \
-o resume.pdf \
https://startupkit.app/api/v1/applications/app_jkl012/resume
Antwort:
-
302 Found– Weiterleitung zur signierten Download-URL. Verwenden Sie-L(Weiterleitungen folgen) mit curl. -
403 Forbidden– Token hat nicht den Scopeapplications:readodercandidates:read. -
404 Not Found– Bewerbung nicht gefunden oder kein Lebenslauf angehängt.
Hinweise:
- Signierte URLs laufen nach 30 Minuten ab. Bei Ablauf fordern Sie eine neue an.
- Der
Content-Disposition-Header ist aufattachmentgesetzt (löst einen Browser-Download aus). - Lebenslauf-Dateitypen: PDF, DOC, DOCX (wie vom Kandidaten hochgeladen).
Schwärzung personenbezogener Kandidatendaten
Wenn ein Token applications:read hat, aber nicht candidates:read, werden die Kandidatendaten in Bewerbungsantworten auf die ID reduziert:
{
"candidate": {
"id": "cand_ghi789"
}
}
Die Felder first_name, last_name und email werden nicht einbezogen. Das metafields-Array und die Lebenslauf-Metadatenfelder entfallen nach derselben Regel vollständig, da auch sie personenbezogene Kandidatendaten enthalten können. Dies ermöglicht es Jobbörsen-Integrationen, den Bewerbungsstatus zu verfolgen, ohne Kontaktinformationen der Kandidaten offenzulegen.
Fehlerbehebung
Authentifizierungsprobleme
401 Unauthorized
Wenn Sie eine 401-Antwort erhalten, prüfen Sie:
- Token-Format: Stellen Sie sicher, dass das Token dem Wert entspricht, der bei der Erstellung einmalig angezeigt wurde (24-stelliger base58-String). Falls Sie ihn nicht mehr haben, widerrufen Sie das Token und erstellen Sie ein neues — Kit speichert nur einen gehashten Digest und kann es nicht erneut anzeigen.
-
Authorization-Header: Muss
Authorization: Bearer TOKENoderAuthorization: token TOKENsein - Token existiert noch: Vergewissern Sie sich, dass das Token unter Einstellungen > API weiterhin aufgeführt ist — ein widerrufenes Token wird gelöscht, nicht deaktiviert
- Kontomitgliedschaft: Stellen Sie sicher, dass der Token-Inhaber noch Mitglied des Kontos ist
403 Forbidden
Wenn Sie eine 403-Antwort erhalten, ist das Token gültig, hat aber nicht den erforderlichen Scope:
-
Erforderliche Scopes prüfen: Jeder Endpunkt dokumentiert seinen erforderlichen Scope (z. B.
job_postings:read) - Fehlende Scopes hinzufügen: Bearbeiten Sie das Token unter Einstellungen > API und fügen Sie den benötigten Scope hinzu
-
Scope-Format: Muss exakt übereinstimmen —
job_postings:read, nichtjob_postingsoderread
Datenzugriffsprobleme
Leeres data-Array in Antworten
Wenn die API {"data": [], "pagination": {...}} zurückgibt, Sie aber Ergebnisse erwarten:
- Kontoisolation: API-Tokens sehen nur Daten ihres zugeordneten Kontos
- Konto überprüfen: Prüfen Sie unter Einstellungen > API, zu welchem Konto das Token gehört
- Kontoübergreifender Zugriff: Tokens können nicht auf Daten anderer Konten zugreifen, selbst wenn der Benutzer Mitglied ist
Kandidaten-PII ist geschwärzt
Wenn Sie nur {"candidate": {"id": "cand_..."}} ohne Name oder E-Mail sehen:
-
Erwartetes Verhalten: Dies geschieht, wenn das Token
applications:readhat, aber nichtcandidates:read -
Scope hinzufügen: Um vollständige Kandidatendetails zu sehen, fügen Sie den Scope
candidates:readzu Ihrem Token hinzu - Privacy by Design: Dies ermöglicht Integrationen, Bewerbungen zu verfolgen, ohne Kontaktinformationen offenzulegen
metafields fehlt in Bewerbungsantworten
Das metafields-Array ist an candidates:read gebunden, nicht an applications:read, denn Metafeld-Werte können von der KI extrahierte personenbezogene Kandidatendaten enthalten. Fehlt in den Antworten der Schlüssel metafields, fehlt dem Token der Scope candidates:read. Fügen Sie diesen Scope nur hinzu, wenn die Integration auch Namen, E-Mail-Adressen und Lebensläufe der Kandidaten sehen soll — beides gehört untrennbar zusammen.
Abfrage- und Filterprobleme
404 beim Abrufen bestimmter Datensätze
-
Präfix-IDs verwenden: Stellenanzeigen verwenden das Format
job_abc123, nicht Datenbank-IDs wie42 - Groß-/Kleinschreibung: Präfix-IDs unterscheiden zwischen Groß- und Kleinschreibung
- Kontozuordnung: Die Ressource muss zum Konto des Tokens gehören
Filterparameter funktionieren nicht
-
Gültige Statuswerte:
- Stellenanzeigen:
draft,published,paused,closed(Groß-/Kleinschreibung beachten) - Bewerbungen:
active,rejected(Groß-/Kleinschreibung beachten)
- Stellenanzeigen:
-
Parameterformat: Verwenden Sie
?status=published, nicht?status=Publishedoder?filter[status]=published
Häufig gestellte Fragen
Wie funktioniert die Paginierung?
Alle Listen-Endpunkte geben 20 Einträge pro Seite zurück (fest). Verwenden Sie ?page=2 für die nächste Seite. Das pagination-Objekt zeigt total_pages und total_count.
Laufen Tokens automatisch ab?
Nein. Beim Erstellen eines Tokens gibt es keine Ablaufeinstellung; ein Token bleibt daher gültig, bis:
- Sie manuell unter Einstellungen > API widerrufen werden
- Der Benutzer aus dem Konto entfernt wird
- Das Konto gelöscht wird
Sollte ich ein Token für mehrere Integrationen verwenden?
Nein. Best Practice ist ein Token pro Integration mit minimalen Scopes. Dies erleichtert:
- Die Überprüfung, welche Integration Anfragen stellt (über
last_used_at) - Den Widerruf des Zugriffs für eine bestimmte Integration, ohne andere zu beeinträchtigen
- Die Vergabe unterschiedlicher Berechtigungen an verschiedene Systeme
Wie hängen Webhooks mit der API zusammen?
Webhooks benachrichtigen Sie über Ereignisse (neue Bewerbung, Phasenwechsel). Die API ermöglicht die Abfrage des aktuellen Zustands. Verwenden Sie Webhooks, um Ihr System auszulösen, und dann die API, um vollständige Details abzurufen.
Kann ich mehr als 20 Einträge pro Seite erhalten?
Nein. Die Seitengröße ist auf 20 Einträge festgelegt, um eine konsistente Leistung zu gewährleisten. Verwenden Sie den page-Parameter, um alle Ergebnisse zu durchlaufen.
Auf einen Blick
- Erstellen Sie ein API-Token unter Einstellungen > API — jedes Token ist an dieses Konto gebunden
- Weisen Sie nur die Scopes zu, die Ihre Integration benötigt (Best Practice: ein Token pro Integration mit minimalen Scopes)
-
Erteilen Sie
candidates:readnur, wenn die Integration personenbezogene Kandidatendaten sehen soll — dieser Scope steuert auch dasmetafields-Array und den Zugriff auf Lebensläufe -
Fügen Sie
Authorization: Bearer TOKENbei jeder Anfrage hinzu -
Verwenden Sie Präfix-IDs (z. B.
job_abc123) in URLs, nicht Datenbank-IDs -
Behandeln Sie
400- und422-Antworten für Validierungsfehler -
Behandeln Sie
401-Antworten — Ihr Token wurde möglicherweise widerrufen -
Behandeln Sie
403-Antworten — Ihrem Token könnte ein erforderlicher Scope fehlen -
Verwenden Sie den
page-Parameter, um große Ergebnismengen zu paginieren (20 Einträge pro Seite)