HTTP API v1 — Entwicklerdokumentation
Überblick
Die API ist für Maschine-zu-Maschine-Zugriffe über OAuth2 Client Credentials gedacht.
Alle geschützten Routen erwarten Authorization: Bearer … und sollten mit
Accept: application/json aufgerufen werden.
Authentifizierung
Token beziehen
POST https://next.integeri.com/oauth/token
Content-Type: application/json
{
"grant_type": "client_credentials",
"client_id": "<UUID des ApiClient> ",
"client_secret": "<Secret des ApiClient> ",
"scope": "*"
}
Antwort enthält u. a. access_token, token_type, expires_in.
HTTP-Status & Fehlerformat
JSON-Fehler für api/* und bei Accept: application/json
| Code | Typische Ursache | Body (vereinfacht) |
|---|---|---|
| 401 | Fehlendes/ungültiges Token | {"message":"Unauthenticated."} |
| 403 | Policy / Berechtigung / inaktiver Service-User | {"message":"…"} |
| 404 | Unbekannte Route oder Model | {"message":"…"} |
| 405 | Falsche HTTP-Methode | {"message":"Method not allowed."} |
| 422 | Validierung | {"message":"…","errors":{…}} |
| 429 | Rate Limit | {"message":"Too many requests."} |
| 500 | Serverfehler | In Produktion generische Meldung; in Dev ggf. Detail |
Listen: Pagination, Sortierung, Filter
Gemeinsame Query-Parameter für GET …/locations, GET …/teams, GET …/users .
| Parameter | Beschreibung |
|---|---|
page | Seite |
per_page | Einträge pro Seite, 1–100 |
sort | Komma-getrennt; Feldname oder -feld für absteigend |
state | active oder inactive (Locations, Teams, Users) |
search | Textsuche (je Ressource unterschiedlich; z. B. Kontaktname) |
Erlaubte Sort-Felder
- Locations:
id,state,created_at,updated_at,order_position - Teams:
id,state,created_at,updated_at,order_position - Users:
id,state,username,created_at,updated_at
Zusätzliche Filter
GET /locations:includeGET /teams:location_id,includeGET /users:team_id,location_id,role,includeGET /courses:state(Standardactive),search(Titel),type(siehe Endpunkt Courses)GET /users/{user}/assigned-courses,GET /users/{user}/certificated-courses: keine Filter
Listen-Antwort: paginiertes JSON mit data, links, meta.
Optional: include
Komma-separierte Liste. Unbekannte Segmente werden ignoriert.
| GET | Segmente | Wirkung (Kurz) |
|---|---|---|
/locations | teams | Liefert eingebettete teams in der Location-Ressource |
/teams | users, instruction | Teammitglieder bzw. wiederkehrende Schulung (Course) |
/users | locations | Zusatzfeld locations (dedupliziert über Team→Location) |
Endpunkte: Auth
Basis: https://next.integeri.com/api/v1 — alle mit Bearer-Token.
GET /auth/me
200 — aktueller Service-User, OAuth-Client, Token-Metadaten
{
"data": {
"service_user": {
"id": 1,
"username": "…",
"company_id": 1,
"roles": ["company.admin", …]
},
"client": { "id": "…", "name": "…" },
"token": {
"expires_at": "2026-01-01T12:00:00+00:00",
"scopes": ["*"]
}
}
}
POST /auth/logout
200 — aktuelles Access Token widerrufen
{ "message": "Token revoked." }
Endpunkte: Locations
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| GET | /locations | Liste | 200 |
| POST | /locations | Anlegen | 201 |
| GET | /locations/{location} | Detail | 200 |
| PUT/PATCH | /locations/{location} | Aktualisieren | 200 |
| POST | /locations/{location}/deactivate | Deaktivieren | 200 |
| PUT | /locations/order-positions | Sortierung mehrerer Standorte | 200 |
| PUT | /locations/{location}/teams/order-positions | Sortierung der Teams eines Standorts | 200 |
POST /locations — Body (Validierung)
name— required, string, max 255description,street,zip_city, …country— max 2 Zeichenadmin_user_ids[],trainer_admin_user_ids[]— optional, User-IDs der Firma
PATCH /locations/{id}
Felder wie Store, alle optional außerhalb von name-Pflicht bei vollem PUT gemäß Client.
PUT /locations/order-positions
Voraussetzung: Berechtigung zum Sortieren von Standorten. Body: {"locations": [{"id": 1, "order_position": 10}, …]} — sortiert Standorte der Firma
PUT /locations/{location}/teams/order-positions
Voraussetzung: Berechtigung zum Sortieren von Teams und Sicht auf den Standort. Body: {"teams": [{"id": 5, "order_position": 20}, …]}.
Endpunkte: Teams
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| GET | /teams | Liste | 200 |
| POST | /teams | Anlegen | 201 |
| GET | /teams/{team} | Detail | 200 |
| PUT/PATCH | /teams/{team} | Aktualisieren | 200 |
| POST | /teams/{team}/deactivate | Deaktivieren | 200 |
| POST | /teams/{team}/users | User dem Team zuordnen | 200 |
| DELETE | /teams/{team}/users/{user} | User aus Team lösen | 204 |
POST /teams — Body
name— requiredlocation_id— required, existiert inlocationsdescription, Kontakt-Felder,admin_user_ids[],trainer_admin_user_ids[]— optional
POST /teams/{team}/users
user_ids— required, Array von User-IDsnext_instruction_date— optional,Y-m-dforce— optional, boolean
Endpunkte: Users
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| GET | /users | Liste | 200 |
| POST | /users | Anlegen | 201 |
| GET | /users/{user} | Detail | 200 |
| PUT/PATCH | /users/{user} | Aktualisieren | 200 |
| POST | /users/{user}/activate | Aktivieren | 200 |
| POST | /users/{user}/deactivate | Deaktivieren | 200 |
| POST | /users/{user}/reset-password | Passwort zurücksetzen | 200 JSON |
| PUT | /users/{user}/roles | Rollen synchronisieren | 200 |
| POST | /users/{user}/course-assignments | Bestehenden Kurs zuweisen | 201 |
| POST | /users/{user}/qualifications | Qualifikation manuell hinterlegen | 201 |
| GET | /users/{user}/assigned-courses | Offene Kurszuweisungen (mit is_overdue) | 200 |
| GET | /users/{user}/certificated-courses | Erledigte Kurse inkl. Zertifikat-URL | 200 |
| GET | /users/{user}/{assignment}/course/{course}-{lang}.pdf | Zertifikat-PDF herunterladen | 200 |
POST /users — Body (Auszug)
salutation—m,f,dfirst_name,last_name— requiredemail,mobile_number,username,password(min 8),language,birthday(Y-m-d),driving_classes(A,CE,D,...)team_ids[],roles[],send_credentials(boolean)id— optional in Service-/Import-Flows; wird für die E-Mail-Unique-Prüfung alsuser_idinterpretiert
Hinweis: Bei Bedarf wird der Benutzername aus Namen/Geburtstag abgeleitet; fehlender optionaler Schlüssel birthday ist erlaubt.
bei 422 die errors prüfen.
PUT /users/{user}/roles
{ "roles": ["company.admin", "company.employee"] }
POST /users/{user}/reset-password
send_email— optional, boolean (Standard in der Regeltrue)
Ohne E-Mail-Versand kann die Antwort ein temporäres Passwort enthalten.
Endpunkte: Courses
Aktive Kurse, die dem aufrufenden Service-User sichtbar sind: Integeri-Kurse und die Kurse der eigenen Firma.
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| GET | /courses | Liste aktiver Kurse (Pagination) | 200 |
Voraussetzung: Berechtigung zum Einsehen von Kursen. Query-Parameter: page, per_page (1–100), state (active/inactive, Standard active), search (Titel), type (optional, siehe unten).
GET /courses — Query-Parameter type
qualification— Qualifikation / manuelle Bestätigung durch Nutzer.operator— nur Bediener-Schulungen .trainer— nur Ausbilder-Schulungen .operator_recurring— nur wiederkehrende Bediener-Unterweisungen .
Ohne type gilt nur die übliche Sichtbarkeitsregel (Integeri + eigene Firma). type schränkt die bereits sichtbaren Kurse weiter ein; Kombination mit search und state ist möglich.
Endpunkte: Content-Video (Prozess)
Legt ein Teleprompter-/Synthese-Video mit prompter_text an —
entweder an einen bestehenden Inhaltsknoten angehängt oder als neuer Inhalt im Unterweisungskurs eines aktiven Basiskurses.
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| POST | /contentvideos/create | Video anlegen / optional neuer Inhalts- und Kursknoten unter Basiskurs | 201 |
Voraussetzung: Berechtigung zum Anlegen von Inhalten; der Ziel-Basiskurs muss zur Firma des Service-Users gehören (oder ein freigegebener Integeri-Basiskurs sein).
Bei Berechtigungsfehler 403 oder Verstoß 422 unter errors.course_id.
POST /contentvideos/create — JSON-Body
prompter_text— Pflicht, String (max. 14000 Zeichen), wird als Prompter-Text des Videos gespeichert.name— optional, String (max. 255 Zeichen). Titel des neuen Inhaltsknotens, wenn keincontent_node_idgesetzt ist. Ohne Angabe wird der Titel aus dem Prompter-Text abgeleitet.content_node_id— optional, positive ID. Wenn gesetzt, muss der Inhaltsknoten existieren; das Video wird dort verknüpft. Sonst wird ein neuer Inhaltsknoten im Zielkurs angelegt.api_base_course_id— optional: positive ID einer API-Kollektion der Firma (muss incompany.video_settings['api-courses']registriert sein) oder-1für eine neue Kollektion. Überschreibt die dem API-Client zugeordnete Kollektion. Ohne Angabe voncourse_id,api_base_course_idundteam_idwird die dem OAuth-Client zugeordneteapi_base_course_idverwendet.course_id— optional, positive ID. Muss ein aktiver Basiskurs oder wiederkehrender Unterweisungskurs sein (z. B.teams.recurring_course_idüberteam_id).team_id— optional, positive ID. Wenn gesetzt und wedercourse_idnochapi_base_course_id(auch nicht-1) angegeben sind, wird der Unterweisungskurs des Teams (teams.recurring_course_id) als Zielkurs verwendet. Typischer Make.com-Flow: zuerst Team anlegen, dann Video mitteam_id.
Fehler 422: unbekannte content_node_id; ungültiger/inaktiver Kurs; Kurs keine registrierte API-Kollektion (api_base_course_id); unbekanntes Team oder Team ohne Unterweisungskurs; Firmen-Mismatch; kein API-Client mit Kollektion; Basiskurs nicht zulässig. 403, wenn die Berechtigung zum Anlegen von Inhalten fehlt .
Erfolg 201, JSON data: content_node_video_id, content_node_id, course_id, course_node_id (nur gesetzt, wenn ein neuer Kursknoten angelegt wurde), estimated_video_length (geschätzte Videolänge in Sekunden aus dem Prompter-Text .
Endpunkte: Course-Assignments (pro User)
| Pfad | Beschreibung | Status | |
|---|---|---|---|
| POST | /users/{user}/course-assignments | Bestehenden Kurs einem User zuweisen | 201 |
| POST | /users/{user}/qualifications | Qualifikation manuell hinterlegen | 201 |
| GET | /users/{user}/assigned-courses | Offene Kurszuweisungen (mit is_overdue) | 200 |
| GET | /users/{user}/certificated-courses | Erledigte Kurse inkl. Zertifikat-URL | 200 |
| GET | /users/{user}/{assignment}/course/{course}-{lang}.pdf | Zertifikat-PDF herunterladen | 200 |
POST /users/{user}/course-assignments
Voraussetzung: Berechtigung zum Anlegen von Kurszuweisungen und Sicht auf den Ziel-Benutzer.
course_id wird gegen die Sichtbarkeit (eigene Firma oder freigegebener Integeri-Kurs) sowie
state = active geprüft.
Die Zuweisung startet mit Status assigned und Typ manual.
POST /api/v1/users/42/course-assignments
Content-Type: application/json
Authorization: Bearer …
{
"course_id": 23,
"deadline_date": "2026-06-30" // optional, Y-m-d oder ISO-8601
}
Antwort 201: eine vollständige CourseAssignment-Ressource (siehe unten).
POST /users/{user}/qualifications
Voraussetzung: Berechtigung zum Anlegen von Kurszuweisungen und Sicht auf den Ziel-Benutzer.
course_id muss ein aktiver Kurs mit Erlaube manuelle Qualifikation sein
(Liste via GET /courses?type=qualification).
Die Zuweisung wird mit state = success und type = approval angelegt.
Datei-Uploads sind in der API v1 nicht enthalten (nur im Web-UI).
POST /api/v1/users/42/qualifications
Content-Type: application/json
Authorization: Bearer …
{
"course_id": 15,
"finish_date": "2024-06-01", // optional, Y-m-d, max. heute
"valid_period": "2y", // optional, z. B. 30d, 6m, 2y; Pflicht, wenn Unternehmen die Gültigkeitsdauer selbst bestimmen kann
"assignment_id": 99 // optional; bestehende approval-Zuweisung aktualisieren
}
Antwort 201: CourseAssignment-Ressource (state=success, assignment_type=approval).
Ablauf (empfohlen)
- Qualifikations-Kurse ermitteln:
GET /courses?type=qualification(nur Kurse mitErlaube manuelle Qualifikation). - User-ID festlegen (z. B. aus
GET /usersoder Import). - Qualifikation hinterlegen:
POST /users/{user}/qualificationsmitcourse_idund optionalfinish_date/valid_period. - Ergebnis prüfen: Antwort enthält die neue Zuweisung; abgeschlossene Einträge erscheinen unter
GET /users/{user}/certificated-coursesmitentry_type = qualification_approval.
JSON-Body — Felder
| Feld | Pflicht | Beschreibung |
|---|---|---|
course_id | ja | Aktiver Qualifikations-Kurs (Erlaube manuelle Qualifikation), sichtbar für die Firma des Service-Users (Integeri-Kurs oder Firmenkurs). |
finish_date | nein | Datum der Qualifikation (Y-m-d), maximal heute. Fehlt die Angabe, wird das aktuelle Datum verwendet. |
valid_period | bedingt | Gültigkeitsdauer, Format ^\d+[d|w|m|y]$ (z.B. 30d, 6m, 2y). Pflicht, Pflicht, wenn das Unternehmen die Gültigkeitsdauer selbst bestimmen kann; sonst wird die des Kurses übernommen. |
assignment_id | nein | Bestehende approval-Zuweisung desselben Users aktualisieren (Datum/Gültigkeit). Muss dem Ziel-User gehören und type = approval sein. |
Verhalten & Voraussetzungen
- Bei Neuanlage (ohne
assignment_id): Zuweisung mitstate = success,type = approval,result_percent = 100; es wird automatisch ein Zertifikat erzeugt . - Der Qualifikations-Kurs muss vollständig konfiguriert sein (mit Kursinhalt) . Sonst schlägt die Zertifikatserstellung fehl → Antwort 422 unter
errors.qualification. - Bestehende gültige
approval-Zuweisungen desselben Users für denselben Kurs werden bei Neuanlage aufvalid_until = gesterngesetzt (ersetzt durch die neue Qualifikation). - Ist der Kurs eine Bedienerschulung, kann — wie in der integeri-Oberfläche — eine wiederkehrende Bediener-Unterweisung ausgelöst werden.
Nach erfolgreicher Anlage erscheint die Qualifikation in GET /users/{user}/certificated-courses
(entry_type = qualification_approval, download_url falls Zertifikat-PDF vorhanden).
Fehlerfälle (422)
course_id— unbekannt, inaktiv, kein Qualifikations-Kurs, oder Kurs einer anderen Firma.finish_date— ungültiges Datum oder liegt in der Zukunft.valid_period— fehlt bei Kurs mitmay_change_valid_period, oder Format ungültig.assignment_id— Zuweisung existiert nicht, gehört nicht zum User, oder ist keinapproval-Typ.qualification— fachlicher Fehler bei der Qualifikationsanlage .
Maschinen-Voraussetzungen (Bediener-/Ausbilderschulung)
Wenn der zugewiesene Kurs eine Bedienerschulung oder Ausbilderschulung ist, werden die kurseigenen Voraussetzungen (Altersnachweis, vorgelagerte Qualifikation, Fitness-Status, etc.) für den Ziel-User geprüft.
Sind nicht alle Voraussetzungen erfüllt, antwortet die API mit
422 Unprocessable Entity. Die fehlgeschlagenen Bedingungen werden als bereits lokalisierte
Textmeldungen unter errors.course_id ausgegeben:
{
"message": "The given data was invalid.",
"ok": 0,
"id": 0,
"errors": {
"course_id": [
"Die Altersüberprüfung (24 Jahre) des Anwenders ist nicht erfüllt.",
"Der erfolgreiche Abschluss der Schulung 'Flurförderfahrzeuge/Stapler - Bediener' fehlt."
]
}
}
Für Nicht-Maschinen-Kurse entfällt dieser zusätzliche Check.
GET /users/{user}/assigned-courses
Voraussetzung: Berechtigung zum Einsehen von Kurszuweisungen und Sicht auf den Ziel-Benutzer. Liefert alle offenen Zuweisungen (Status assigned, inprogress, done sowie success
innerhalb laufender Gruppen-/Bedienerschulungen). Das Feld is_overdue markiert überfällige Einträge
(deadline_date liegt in der Vergangenheit).
GET /users/{user}/certificated-courses
Voraussetzung: Berechtigung zum Einsehen abgeschlossener Kurse und Sicht auf den Ziel-Benutzer. Liefert abgeschlossene Zuweisungen als certificated_course-Ressourcen mit lokalisiertem
state_label (wie Web-Zertifikatsliste, z. B. „Bestanden“ / „Teilgenommen“ — nicht roh
success/failed). Das Feld download_url verweist auf die API-PDF-Route
GET /users/{user}/{assignment}/course/{course}-{lang}.pdf (generierte Zertifikate) oder auf eine
signierte Upload-Datei-URL — dieselben Regeln wie in der Web-Zertifikatsliste .
Hinweis: Wiederholungen und Gruppen-/Bedienerschulungen werden serverseitig dedupliziert
GET /users/{user}/{assignment}/course/{course}-{lang}.pdf
Voraussetzung: Berechtigung zum Einsehen abgeschlossener Kurse und Sicht auf den Ziel-Benutzer. Liefert das Zertifikat als PDF-Datei (dieselben Download-Regeln wie in der integeri-Oberfläche).
Nur für abgeschlossene Zuweisungen (state = success oder failed), deren
user_id, assignment-ID und course-ID zur URL passen.
{lang} ist ein zweistelliger Sprachcode (z. B. de, en).
GET /api/v1/users/42/99/course/15-de.pdf
Authorization: Bearer …
Antwort 200: PDF-Datei.
JSON-Ressourcen (Felder)
Vereinfachte Übersicht;
Location
id, type (= location), state, description, company_id, contact (Objekt), admin_user_ids, trainer_admin_user_ids, teams_count, optional teams bei include=teams, Zeitstempel.
Team
id, type (= team), state, description, location_id, contact, Zuweisungen, users_count, optional users / instruction, Zeitstempel.
User
id, type (= user), state, username, Kontakt-/Profilfelder, company_id, team_ids, roles, optional locations bei include=locations, Zeitstempel.
Course
id, type (= course), title, description,
allow_user_approval_date (boolean), valid_period, number_of_questions,
minimal_success_points, state, company_id (null für Integeri-Kurse).
CourseAssignment
Verwendet für POST /users/{user}/course-assignments, POST /users/{user}/qualifications und GET /users/{user}/assigned-courses.
id,type(=course_assignment),user_idstate—assigned,inprogress,done,success,failed,notshownupassignment_type—manual,recurring,approvaldeadline_date,valid_until,begin_date,finish_date(ISO-8601 bzw.Y-m-d)result_percent— Prozent korrekt beantworteter Fragen, odernullis_overdue— boolean,truewenndeadline_date < now()course—{id, title, short_type, scope_id, type}trainer—{id, full_name}odernullcreator—{id, full_name}odernullcreated_at,updated_at
CertificatedCourse
Verwendet für GET /users/{user}/certificated-courses (abgeschlossene Zuweisungen ).
id,user_identry_type—certificated_course(fürmanual),qualification_approval(fürapproval),operator_training(Gruppen-Bediener),trainer_training(Ausbilder-Kurs)state_label— lokalisiertes Kurz-Ergebnis (Schulung/Unterweisung), kein rohesstateassignment_type— DB-Typ der Zuweisungfinish_date,valid_until,result_percentis_group_operator_training— booleancourse—{id, title, short_type}download_url— API-PDF-URL (/api/v1/users/…/course/{course}-{lang}.pdf) oder signierte Upload-URLcreated_at,updated_at
Referenzen
- PHP Mini-SDK (ZIP):
/docs/api/integeri-sdk-php.zip - Make.com-Integration (PDF):
/docs/api/integeri-api-make-com.pdf— Team/Video-Flow und Zertifikat-PDF-Download