Public Job API
Öffentliche REST-Schnittstelle für Karriereseiten, Job-Boards und Partner-Integrationen. Alle hier dokumentierten Endpoints sind ohne Authentifizierung erreichbar.
- Base URL:
https://api.regrooter.de - Version:
v1(Bestandteil des Pfads) - Content-Type:
application/json; charset=utf-8 - Interaktive Spec: https://api.regrooter.de/q/swagger-ui · Rohformat: https://api.regrooter.de/q/openapi
Schnellstart
# Erste Seite der offenen Stellen von "regrooter"
curl -s "https://api.regrooter.de/v1/jobs/regrooter?page=0&size=20"
{
"content": [ { "id": 339, "title": "Senior Java Entwickler (m/w/d)", "...": "..." } ],
"page": 0,
"size": 20,
"totalElements": 137,
"totalPages": 7,
"first": true,
"last": false,
"sort": "createdAt,desc"
}
Alle Seiten durchlaufen:
page=0
while :; do
body=$(curl -s "https://api.regrooter.de/v1/jobs/regrooter?page=$page&size=100")
echo "$body" | jq -r '.content[] | .canonicalId'
[ "$(echo "$body" | jq -r '.last')" = "true" ] && break
page=$((page + 1))
done
Grundbegriffe
| Begriff | Bedeutung |
|---|---|
| companySlug | Stabile Kennung einer Karriereseite, z. B. regrooter. Wird von Regrooter vergeben und ändert sich nicht. |
jobSlug (canonicalId) | Stabile Kennung einer einzelnen Stellenanzeige, z. B. senior-java-entwickler-hamburg-339. Wird für Detailabruf und Bewerbung verwendet. |
| Publication | Veröffentlichung einer Stelle auf einem Kanal. Diese API liefert ausschließlich die Veröffentlichungen auf dem Kanal WEBSITE (Karriereseite). |
| aktiv | Eine Stelle erscheint in der Liste, wenn ihre Publication aktiv ist, die Karriereseite aktiv ist und validThrough in der Zukunft liegt oder leer ist. |
Sichtbarkeitsregeln, die serverseitig erzwungen werden und über die API nicht umgangen werden können:
- Interne VMS-Anfragen (
vmsOnly) erscheinen nie. - Gehaltsangaben werden nur ausgeliefert, wenn die Stelle sie freigibt (
showSalaryOnJobAdd). Andernfalls istsalarynull. - E-Mail und Telefonnummer des Ansprechpartners werden nur ausgeliefert, wenn die Karriereseite das erlaubt. Andernfalls sind die Felder
null, während Name und Avatar bestehen bleiben.
CORS und Aufrufmuster
Die API setzt Access-Control-Allow-Origin nur für die Regrooter-Domains und für Kundendomains, die als Custom Domain registriert und verifiziert sind. Für eine Integration bedeutet das:
| Muster | Funktioniert | Hinweis |
|---|---|---|
| Server-zu-Server (PHP, Node, Python, CMS-Plugin, Cronjob) | ✅ | Empfohlen. CORS ist irrelevant, Antworten lassen sich cachen. |
| Browser-Fetch von eigener Domain | ❌ | Wird blockiert, solange die Domain nicht bei Regrooter registriert ist. |
| Browser-Fetch von registrierter Custom Domain | ✅ | Registrierung über Regrooter anfragen. |
Die praktikable Variante für eine Agentur ist ein dünner Proxy in der eigenen Anwendung: der Server ruft die API auf, cached die Antwort und liefert sie an das eigene Frontend aus.
Stellenliste (paginiert)
GET /v1/jobs/{companySlug}
Liefert die aktiven Stellen einer Karriereseite als Pagination-Envelope.
Pfadparameter
| Name | Typ | Beschreibung |
|---|---|---|
companySlug | string | Slug der Karriereseite |
Query-Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
page | integer | 0 | 0-basierter Seitenindex |
size | integer | 10 | Treffer pro Seite, erlaubt 1–100 |
sort | string | createdAt,desc | feld[,asc|desc]. Felder: createdAt, publishDate, title |
title | string | – | Teilstring-Suche im Stellentitel, Groß-/Kleinschreibung egal |
salary | integer | – | Mindestgehalt. Trifft, wenn das Maximum der Stelle ≥ Wert ist (bzw. das Minimum, falls kein Maximum gepflegt ist) |
lat | number | – | Breitengrad des Suchmittelpunkts (WGS84) |
lon | number | – | Längengrad des Suchmittelpunkts (WGS84) |
radius | integer | 25 | Umkreis in Metern |
industries | integer | – | Branchen-IDs, siehe Filterwerte |
contracts | enum | – | ContractType |
seniorities | enum | – | JobSeniority |
workplaces | enum | – | WorkplaceType |
employments | enum | – | EmploymentType |
workschedules | enum | – | WorkSchedule |
Mehrwertige Parameter werden als wiederholter Schlüssel übergeben, nicht kommasepariert:
?contracts=PERMANENT&contracts=FREELANCE&industries=12&industries=15
Umkreissuche greift nur, wenn lat, lon und radius gemeinsam gesetzt sind. Ein einzelnes lat ohne lon wird ignoriert. Stellen ohne hinterlegten Standort fallen bei aktiver Umkreissuche aus dem Ergebnis.
Alle Filter werden mit UND verknüpft, Werte innerhalb eines mehrwertigen Filters mit ODER.
Antwort 200
{
"content": [
{
"id": 339,
"title": "Senior Java Entwickler (m/w/d)",
"canonicalId": "senior-java-entwickler-hamburg-339",
"description": "<p>Für unseren Kunden suchen wir …</p>",
"publishDate": "2026-08-14T09:12:00",
"validThrough": "2026-11-14T00:00:00",
"publicationStatus": "PUBLISHED",
"workplaceType": "HYBRID",
"employmentType": "FULL_TIME",
"contractType": "PERMANENT",
"workSchedule": "FLEXTIME",
"industryName": "IT und Softwareentwicklung",
"jobUri": "https://regrooter.de/jobs/regrooter/senior-java-entwickler-hamburg-339",
"salary": {
"salaryFrequency": "YEARLY",
"currency": "EUR",
"minSalary": 70000,
"maxSalary": 90000,
"showSalaryOnJobAdd": true
},
"location": {
"id": 2911298,
"city": "Hamburg",
"state": "Hamburg",
"cityState": "Hamburg, Hamburg",
"county": "Hamburg",
"countryCode": "DE",
"zip": "20095",
"lat": 53.5511,
"lon": 9.9937
},
"company": {
"companyName": "Regrooter GmbH",
"companySlug": "regrooter",
"companyLogoUrl": "https://cdn.regrooter.de/logos/regrooter.png"
},
"pointOfContact": {
"firstname": "Max",
"lastname": "Mustermann",
"fullname": "Max Mustermann",
"email": "[email protected]",
"phonenumber": "+49 40 1234567",
"avatarUrl": "https://cdn.regrooter.de/avatars/platzhalter.png"
}
}
],
"page": 0,
"size": 10,
"totalElements": 137,
"totalPages": 14,
"first": true,
"last": false,
"sort": "createdAt,desc"
}
Hinweise zur Paginierung
- Seiten sind 0-basiert: die erste Seite ist
page=0. - Zum Beenden einer Schleife
lastauswerten, nichtcontent.length. - Eine Seite hinter dem letzten Treffer liefert
200mit leeremcontentund korrektemtotalElements, nicht404. - Die Sortierung ist stabil: bei gleichem Sortierwert entscheidet die Publication-ID absteigend. Ein Datensatz kann dadurch beim Durchblättern nicht doppelt oder gar nicht erscheinen.
totalElementsberücksichtigt alle gesetzten Filter.- Stellen, die sich während des Durchblätterns ändern, können die Seitenaufteilung verschieben. Für einen konsistenten Vollabzug empfiehlt sich
sort=createdAt,descmitsize=100.
Statuscodes
| Code | Bedeutung |
|---|---|
200 | Seite mit Treffern, ggf. leer |
400 | page negativ, size außerhalb 1–100, oder unbekanntes sort-Feld / unbekannte Richtung |
404 | Kein aktives Karriereseiten-Setting für diesen Slug |
Einzelne Stelle
GET /v1/jobs/{companySlug}/{jobSlug}
Liefert eine einzelne Stelle inklusive vollständiger Beschreibung. Das Antwortobjekt ist ein Job ohne Envelope.
curl -s "https://api.regrooter.de/v1/jobs/regrooter/senior-java-entwickler-hamburg-339"
Abgelaufene und zurückgezogene Stellen werden bewusst weiter ausgeliefert, damit bereits verlinkte oder indexierte Detailseiten kein 404 erzeugen. Der Endpoint liefert also auch Stellen, die in der Liste aus Stellenliste nicht mehr auftauchen.
Zwei Felder zeigen den Zustand an, beide sollten vor der Anzeige geprüft werden:
| Signal | Bedeutung |
|---|---|
validThrough liegt in der Vergangenheit | Die Anzeige ist abgelaufen |
publicationStatus ist nicht PUBLISHED | Die Anzeige wurde zurückgezogen oder geschlossen |
Trifft eines davon zu, sollte die Seite als „Stelle nicht mehr verfügbar" dargestellt und keine Bewerbung mehr angeboten werden.
Der companySlug im Pfad muss zur Stelle gehören — ein Job eines anderen Kunden ist unter dem eigenen Slug nicht abrufbar.
| Code | Bedeutung |
|---|---|
200 | Die Stelle |
404 | Kein Job mit diesem Slug, oder der Job gehört nicht zu diesem companySlug |
Filterwerte
GET /v1/jobs/filters/{companySlug}
Liefert die Filteroptionen für eine Karriereseite: die für diese Company freigeschalteten Branchen sowie die Enum-Filter mit deutschen Labels. Damit lässt sich eine Filter-UI aufbauen, ohne Werte fest zu verdrahten.
{
"industries": [
{ "id": 12, "name": "IT und Softwareentwicklung", "level": 1, "sortOrder": 10 }
],
"seniorities": [ { "key": "SENIOR", "label": "Senior" } ],
"contracts": [ { "key": "PERMANENT", "label": "Festanstellung" } ],
"workplaces": [ { "key": "HYBRID", "label": "Hybrid" } ],
"employments": [ { "key": "FULL_TIME", "label": "Vollzeit" } ],
"workschedules": [ { "key": "FLEXTIME", "label": "FLEXTIME" } ]
}
key ist der Wert, der an die Stellenliste übergeben wird; label ist die Anzeigebezeichnung. Für Werte ohne hinterlegte Übersetzung entspricht label dem key.
Die Branchenliste ist company-spezifisch — industries-IDs aus einer anderen Karriereseite treffen unter Umständen nichts.
Eine Variante über die technische Company-ID steht unter GET /v1/jobs/filters/company/{companyId} bereit.
Standorte
GET /v1/locations
Liefert die größeren Städte mit Koordinaten. Aus diesem Ergebnis stammen die lat/lon-Werte für die Umkreissuche.
[ { "id": 2911298, "city": "Hamburg", "state": "Hamburg", "countryCode": "DE", "lat": 53.5511, "lon": 9.9937 } ]
Die Liste ist umfangreich und ändert sich selten — einmal täglich abrufen und lokal vorhalten.
Branding
GET /v1/branding/{companySlug}
Liefert Name, Logo, Hero-Bild und Farbschema. Nützlich, um eine eingebettete Jobliste im Erscheinungsbild des Kunden darzustellen.
{
"name": "Regrooter GmbH",
"logo": "https://cdn.regrooter.de/logos/regrooter.png",
"heroImage": "https://cdn.regrooter.de/hero/regrooter.jpg",
"heroHeadline": "Arbeiten bei Regrooter",
"heroSubtext": "Finde deinen nächsten Schritt.",
"theme": { "primary": "#1a73e8", "secondary": "#0c4a6e" },
"companySlug": "regrooter",
"customDomain": "jobs.beispielkunde.de"
}
Zusätzlich existiert GET /v1/branding?domain=jobs.beispielkunde.de zur Auflösung einer Custom Domain auf den zugehörigen companySlug.
Schlanke Liste für Sitemaps
GET /v1/seo/jobs/{companySlug}
Liefert alle aktiven Job-Slugs mit Änderungsdatum, ohne Paginierung und ohne Beschreibungstexte. Für Sitemap-Generierung und Delta-Abgleich deutlich günstiger als die vollständige Stellenliste.
[ { "canonicalId": "senior-java-entwickler-hamburg-339", "updatedAt": "2026-09-02T11:04:00" } ]
Bewerbung einreichen
POST /v1/jobs/{companySlug}/{jobSlug}/apply
Content-Type: multipart/form-data
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| beliebiger Feldname | Datei | ja | Bewerbungsunterlagen. Mehrere Dateien sind erlaubt; alle Datei-Parts werden übernommen. |
frc-captcha-response | string | ja | Token aus dem Friendly-Captcha-Widget |
Attributionsdaten werden aus dem Query-String übernommen: source, utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id, referrer/referer. Zusätzlich wird der Referer-Header ausgewertet.
curl -X POST \
"https://api.regrooter.de/v1/jobs/regrooter/senior-java-entwickler-hamburg-339/apply?utm_source=agentur-xy&utm_medium=jobboard" \
-F "[email protected]" \
-F "frc-captcha-response=<token>"
- Der Endpoint antwortet mit
204 No Content— auch dann, wenn das Captcha-Token ungültig ist und die Bewerbung verworfen wird. Aus der Antwort lässt sich nicht ableiten, ob die Bewerbung angekommen ist. - Ein gültiges Friendly-Captcha-Token erfordert das Widget im Browser des Bewerbers. Eine rein serverseitige Einreichung ist ohne gesonderte Absprache nicht möglich.
View- und Click-Tracking
POST /v1/track-view/jobs
Content-Type: application/json
Optional; meldet einen Seitenaufruf einer Stellenanzeige an die Reporting-Auswertung des Kunden.
{
"tenant": "regrooter",
"slug": "senior-java-entwickler-hamburg-339",
"utm_source": "agentur-xy",
"utm_medium": "jobboard",
"utm_campaign": "herbst-2026",
"source": "agentur-xy",
"referer": "https://jobs.agentur-xy.de/"
}
tenant und slug sind Pflicht. Antwort: 204 bei Erfolg, 404, wenn die Stelle nicht gefunden wurde.
Für Klicks auf einen ausgehenden Link steht POST /v1/track-view/jobs/click mit identischem Body bereit.
Datenmodelle
PagedResponse
| Feld | Typ | Beschreibung |
|---|---|---|
content | array | Treffer der Seite, nie null |
page | integer | 0-basierter Index der gelieferten Seite |
size | integer | Angeforderte Seitengröße, nicht die tatsächliche Länge von content |
totalElements | integer | Gesamttrefferzahl über alle Seiten, unter Berücksichtigung aller Filter |
totalPages | integer | Anzahl Seiten, 0 bei keinem Treffer |
first | boolean | true auf der ersten Seite |
last | boolean | true auf der letzten Seite — Abbruchkriterium für Schleifen |
sort | string | Tatsächlich angewendete Sortierung |
Job
| Feld | Typ | Beschreibung |
|---|---|---|
id | integer | Technische Job-ID. Für Verlinkungen canonicalId verwenden. |
title | string | Stellentitel |
canonicalId | string | Slug der Stelle, Eingabe für Detailabruf und Bewerbung |
description | string | Stellenbeschreibung als HTML |
publishDate | datetime | Veröffentlichungszeitpunkt, ISO-8601 ohne Zeitzone (Europe/Berlin) |
validThrough | datetime | Ende der Gültigkeit, null = unbefristet |
publicationStatus | enum | PublicationStatus |
workplaceType | enum | WorkplaceType |
employmentType | enum | EmploymentType |
contractType | enum | ContractType |
workSchedule | enum | WorkSchedule |
industryName | string | Branchenbezeichnung |
jobUri | string | Kanonische URL der Stelle. Für SEO als rel="canonical" setzen, wenn die Stelle auf einer fremden Seite gespiegelt wird. |
salary | object | Salary oder null, wenn das Gehalt nicht veröffentlicht wird |
location | object | Location |
company | object | Company |
pointOfContact | object | Contact oder null |
Salary
| Feld | Typ | Beschreibung |
|---|---|---|
salaryFrequency | enum | SalaryFrequency |
currency | string | ISO-4217, z. B. EUR |
minSalary | integer | Untergrenze, kann null sein |
maxSalary | integer | Obergrenze, kann null sein |
showSalaryOnJobAdd | boolean | Immer true, wenn das Objekt geliefert wird |
Location
| Feld | Typ | Beschreibung |
|---|---|---|
id | integer | Standort-ID, passend zu /v1/locations |
city | string | Ort |
state | string | Bundesland |
cityState | string | Kombinierte Anzeige, z. B. Hamburg, Hamburg |
county | string | Regierungsbezirk / Kreis |
countryCode | string | ISO-3166-1 alpha-2 |
zip | string | Postleitzahl |
lat, lon | number | Koordinaten (WGS84) |
Company
| Feld | Typ | Beschreibung |
|---|---|---|
companyName | string | Anzeigename |
companySlug | string | Slug der Karriereseite |
companyLogoUrl | string | Logo-URL, kann null sein |
Contact
Ansprechpartner der Stelle. E-Mail und Telefon erscheinen nur, wenn die Karriereseite sie freigibt.
| Feld | Typ | Beschreibung |
|---|---|---|
firstname, lastname | string | Name |
fullname | string | Abgeleitet aus Vor- und Nachname |
email | string | null, wenn nicht freigegeben |
phonenumber | string | null, wenn nicht freigegeben |
avatarUrl | string | Profilbild, kann null sein |
Enum-Referenz
Enum-Werte werden als Großbuchstaben-Konstanten übertragen und bei Filtern exakt so erwartet. Anzeigelabels liefert der Endpoint Filterwerte.
ContractType
| Wert | Bedeutung |
|---|---|
PERMANENT | Festanstellung |
FIXED_TERM | Zeitlich befristet |
FREELANCE | Freelancer |
TEMP_AGENCY | Arbeitnehmerüberlassung |
INTERNSHIP | Praktikum |
WORKING_STUDENT | Werkstudent |
APPRENTICESHIP | Ausbildung |
EmploymentType
| Wert | Bedeutung |
|---|---|
FULL_TIME | Vollzeit |
PART_TIME | Teilzeit |
MINI_JOB | Minijob |
OTHER | Andere |
WorkplaceType
| Wert | Bedeutung |
|---|---|
ONSITE | Vor Ort |
HYBRID | Hybrid |
REMOTE | Remote |
JobSeniority
| Wert | Bedeutung |
|---|---|
INTERN | Praktikant |
JUNIOR | Berufseinsteiger |
PROFESSIONAL | Fachkraft |
SENIOR | Spezialist |
LEAD | Teamlead |
MANAGER | Manager |
EXECUTIVE | Geschäftsführung |
WorkSchedule
| Wert | Bedeutung |
|---|---|
REGULAR | Regelarbeitszeit |
SHIF_WORK | Schichtarbeit (Schreibweise historisch bedingt) |
FLEXTIME | Gleitzeit |
ON_CALL | Auf Abruf |
SalaryFrequency
| Wert | Bedeutung |
|---|---|
HOURLY | pro Stunde |
DAILY | pro Tag |
WEEKLY | pro Woche |
MONTHLY | pro Monat |
YEARLY | pro Jahr |
PublicationStatus
Status der Veröffentlichung. Über die Public API erscheinen praktisch ausschließlich aktive Veröffentlichungen; der Wert wird der Vollständigkeit halber mitgeliefert.
| Wert | Bedeutung |
|---|---|
DRAFT | Entwurf |
PENDING | Veröffentlichung läuft |
PUBLISHED | Veröffentlicht |
FAILED | Veröffentlichung fehlgeschlagen |
PARTIALLY_FAILED | Teilweise fehlgeschlagen |
UNPUBLISHED | Zurückgezogen |
CLOSED | Geschlossen |
ARCHIVED | Archiviert |
Fehlerbehandlung
Fehler werden einheitlich als JSON zurückgegeben:
{
"errorCode": "COMPANY_NOT_FOUND",
"message": "Company with slug 'gibtsnicht' not found",
"status": 404
}
| Status | errorCode | Typische Ursache |
|---|---|---|
400 | BAD_REQUEST | page negativ, size außerhalb 1–100, unbekanntes sort-Feld |
404 | COMPANY_NOT_FOUND | Unbekannter companySlug oder jobSlug |
500 | INTERNAL_SERVER_ERROR | Serverseitiger Fehler |
message ist für Menschen gedacht und kann sich ändern — Auswertungen bitte auf status und errorCode stützen.
Betriebshinweise
Caching. Stellenanzeigen ändern sich selten. Empfohlen: Listen 5–15 Minuten, Detailseiten 15–60 Minuten, /v1/locations und die Filterwerte bis zu 24 Stunden serverseitig cachen. Die API sendet aktuell keine ETag- oder Cache-Control-Header.
Lastverhalten. Es gibt derzeit kein hartes Rate-Limit. Für einen Vollabzug size=100 verwenden und Requests seriell absetzen; bitte nicht parallel über alle Seiten fahren. Regrooter behält sich vor, Rate-Limits einzuführen — dann würden sie mit 429 und Retry-After beantwortet.
Delta-Abgleich. Für einen periodischen Sync ist /v1/seo/jobs/{companySlug} der günstigste Einstieg: updatedAt je Slug abgleichen und nur geänderte Stellen im Detail nachladen.
SEO. Wird eine Stelle auf einer fremden Seite gespiegelt, sollte jobUri als rel="canonical" gesetzt werden, damit die Original-Anzeige nicht als Duplicate Content abgewertet wird.
Zeitangaben. Alle Datumsfelder sind ISO-8601 ohne Zeitzonen-Offset und beziehen sich auf Europe/Berlin.
Support. [email protected]