Element External Integration API — dokumentacja

v1-beta dokument v1.4 · 2026-07-23 Beta

REST API do integracji zewnętrznych systemów (voice-boty, ATS, pipeline'y danych) z platformą Element. Interfejs jest w fazie beta — kontrakt może się jeszcze zmienić w niekompatybilny sposób w oknie ~2–3 miesięcy testów produkcyjnych; zmiany łamiące będą komunikowane z wyprzedzeniem.

◆ Zmiany w wersji 1.4 (2026-07-23)
  • GET …/application-form — zgody RODO projektu. Nowe addytywne pole consents[] z definicjami zgód projektu (hash, type, name, content, required, allowsCommunication). Zob. 8.6.
  • POST …/apply — przekazywanie zaakceptowanych zgód. Nowe opcjonalne pole consents[] (hashe zgód z GET) rejestruje zgody kandydata — widoczne w zakładce RODO i honorowane przez filtry zgód. Nieznany hash → 400 invalid_consents. Zob. 8.11.
  • POST …/apply — pliki jako odpowiedzi na pytania formularza. Nowe opcjonalne pole answerFiles[<questionId>][] pozwala przesłać pliki do pytań plikowych formularza (do 10 plików łącznie, 5 MB każdy). Błędne mapowanie → 400 invalid_answer_files. Zob. 8.11.
  • POST …/apply — automatyczne wiadomości do kandydata. Aplikacja przez API uruchamia teraz te same automatyczne wiadomości do kandydata co aplikacja przez formularz webowy (np. podziękowanie za aplikację, akcje etapu aplikacyjnego), o ile tenant ma je skonfigurowane. Bez zmian w kontrakcie. Zob. 8.11.

Wszystkie zmiany 1.4 są opcjonalne i addytywne — integracja zbudowana na 1.3 działa bez modyfikacji. Zmiany z wersji 1.2 (rozwinięte subForms[], załączniki attachments[], odpowiedzi calendarDay) i 1.3 (opcjonalny email, dane podstawowe w podglądzie formularza) pozostają oznaczone znaczkami „v1.2"/„v1.3" w sekcjach 8.6 i 8.11.


1O API

External Integration API udostępnia programowy dostęp tylko-do-odczytu do projektów rekrutacyjnych, kandydatów i formularzy aplikacyjnych oraz ograniczony zestaw operacji zapisu (utworzenie kandydata przez aplikację, dodanie publicznej notatki). Adresowany jest do zespołów developerskich wdrażających integracje z systemami zewnętrznymi.

Wszystkie ścieżki są wersjonowane prefiksem /api/v1-beta. Po stabilizacji interfejs przejdzie w zamrożone v1; przyszłe zmiany łamiące trafią pod nowy prefiks (np. /api/v2).

2Wymagania wstępne

  • Aktywny tenant Element z włączonym modułem External Integration API.
  • Konto API (login + hasło) utworzone w panelu — jeden zestaw poświadczeń na jeden system zewnętrzny.
  • Klient HTTP obsługujący uwierzytelnianie HTTP Basic oraz multipart/form-data (dla przesyłania plików).

3Pierwsze wywołanie

Najprostszy test łączności — endpoint health (bez uwierzytelniania):

curl https://<tenant>.elementapp.ai/api/v1-beta/health

# 200 OK
{ "status": "ok", "apiVersion": "v1-beta" }

Kolejny krok — uwierzytelnione pobranie listy projektów (zob. 8.2).

4Uwierzytelnianie

Schemat: HTTP Basic (RFC 7617), realm External Integration API.

  • login — w formacie api+<nazwa-systemu>@<tenant>.local (np. api+voicebot@acme.local).
  • hasło — generowane losowo, pokazywane jednorazowo przy utworzeniu, nieodzyskiwalne.
  • nagłówekAuthorization: Basic base64(login:hasło).

Wielotenantowość: tenant identyfikowany jest wyłącznie po subdomenie w URL (<tenant>.elementapp.ai); poświadczenia są zablokowane do jednego tenanta.

⚠ Ochrona przed brute-force
  • (IP + login): 5 nieudanych prób → blokada 15 min.
  • sam login: 20 nieudanych prób → blokada 15 min.
  • Odpowiedź: 429 z kodem too_many_failed_attempts.

5Format danych

  • Odpowiedziapplication/json; charset=utf-8.
  • Żądaniaapplication/x-www-form-urlencoded lub multipart/form-data (dla plików).
  • Daty — ISO 8601 UTC z offsetem (2026-05-28T12:34:56+00:00); daty-tylko jako YYYY-MM-DD.
  • Identyfikatory — UUID v4 (np. ff315ea1-c056-472d-aefe-b99f3d41e5c0).
  • Lokalizacja — parametr locale (pl, en, de, …) dla schematu formularza i odpowiedzi.

Koperta odpowiedzi (sukces):

{ "data": { /* encja lub tablica */ },
  "meta": { "page": 1, "perPage": 20, "total": 8 } }

Koperta odpowiedzi (błąd):

{ "error": { "code": "snake_case_identifier",
             "message": "Czytelny opis (dla wybranych kodów)" } }

Paginacja: ?page=N&perPage=N (1–100, domyślnie 20); w odpowiedzi meta: { page, perPage, total }.

6Limity zapytań

  • Domyślnie: 70 wywołań/min na poświadczenie (60 bazowe + 10 burst) ≈ 1,2 req/s.
  • Odpowiedź przy przekroczeniu: 429 z kodem rate_limit_exceeded.
  • Backoff: wykładniczy od 1 s, limit 30 s.
  • Wyższe limity — kontakt ze wsparciem Element.

7Obsługa błędów

HTTPcodeZnaczenie
200Sukces (GET)
201Utworzono (POST)
400validation_failedNieprawidłowe/niekompletne żądanie
400invalid_answersPOST /apply: błędny JSON lub kształt/wartości answers
400invalid_consentsv1.4POST /apply: hash w consents[] nie pasuje do żadnej definicji zgody projektu
400invalid_answer_filesv1.4POST /apply: błędny klucz answerFiles (nieznane / nieplikowe pytanie), zła liczba plików lub przekroczony limit 10 plików
401Brak / błędne uwierzytelnianie
403Brak roli lub konto dezaktywowane
404project_not_foundProjekt nie istnieje / zarchiwizowany / spoza tenanta
404candidate_not_foundKandydat nie istnieje / zarchiwizowany / usunięty RODO
404application_form_not_foundBrak formularza / niewypełniony przez kandydata
409no_application_stageProjekt bez etapu aplikacyjnego
409stale_form_versionPOST /apply: niezgodna wersja formularza
429rate_limit_exceededPrzekroczony limit zapytań
429too_many_failed_attemptsBlokada po nieudanych logowaniach
5xxBłąd serwera Element; ponów z backoffem

8Referencja endpointów

Base URL: https://<tenant>.elementapp.ai/api/v1-beta

8.1 — Health check

GET/health

Kontrola łączności bez uwierzytelniania.

{ "status": "ok", "apiVersion": "v1-beta" }

8.2 — Lista projektów

GET/projects?page={n}&perPage={n}

Stronicowana lista aktywnych projektów.

{ "data": [
    { "id": "ff315ea1-…", "name": "Senior PHP Developer",
      "positionName": null, "isRemote": true,
      "statusId": "73f09ef2-…", "createdAt": "2021-10-31T11:42:24+00:00" } ],
  "meta": { "page": 1, "perPage": 20, "total": 8 } }

Błędy: 401, 429.

8.3 — Szczegóły projektu

GET/projects/{projectId}

Pełne dane projektu wraz z listą etapów. Pola responsibilities, requirements, offer zawierają treść HTML. minimumSalary/maximumSalary w walucie tenanta (0 = nieustawione).

{ "data": { "id": "ff315ea1-…", "name": "Senior PHP Developer",
    "minimumSalary": 12000, "maximumSalary": 18000, "numberOfVacancies": 4,
    "stages": [
      { "id": "…", "name": "Aplikacja", "isApplicationType": true },
      { "id": "…", "name": "Rozmowa", "isApplicationType": false } ] } }

Błędy: 401, 404 project_not_found, 429.

8.4 — Etapy projektu

GET/projects/{projectId}/stages

Sama tablica etapów (kształt jak data.stages z 8.3). Etap o isApplicationType: true to etap aplikacyjny (max jeden na projekt).

Błędy: 401, 404 project_not_found, 429.

8.5 — Kandydaci w projekcie

GET/projects/{projectId}/candidates?page={n}&stageId={uuid}

Stronicowana lista kandydatów; opcjonalny filtr stageId. Pola: id, firstName, lastName, email, stageId, isRejected, addedAt. Pole email może być puste — od v1.3 aplikację przez API można złożyć bez adresu e-mail (zob. 8.11).

Błędy: 401, 404 project_not_found, 429.

8.6 — Schemat formularza aplikacyjnego ZMIANA v1.4

GET/projects/{projectId}/application-form

Zwraca pełną strukturę formularza (metadane + zagnieżdżone sekcje → pytania → warianty odpowiedzi). Użyj do zbudowania mapy odpowiedzi, pobrania version oraz — od v1.4 — hashy zgód do POST /apply.

◆ Nowość v1.4 — definicje zgód RODO projektu

Odpowiedź zawiera teraz addytywne pole consents[] — definicje zgód RODO projektu: hash (identyfikator wersji treści zgody — dokładnie tę wartość odsyłasz w consents[] w POST /apply, by zarejestrować akceptację), type (np. recruitmentProcess — zgoda na tę rekrutację, futureRecruitmentProcess — zgoda na przyszłe procesy), name, content (pełna treść — tę treść masz obowiązek pokazać kandydatowi przed zebraniem zgody), required (flaga informacyjna — API jej nie egzekwuje, zob. 8.11) i allowsCommunication. Projekt bez zdefiniowanych zgód zwraca pustą tablicę.

◆ Nowość v1.2 — rozwinięte podformularze

Każda sekcja zwraca tablicę subForms[] z pełną, rozwiniętą strukturą podformularza (np. calendar-days, week-days) — zagnieżdżone sekcje i pytania. Wcześniej dostępne były wyłącznie identyfikatory. Pole subFormIds pozostaje jako powiązanie sekcja→podformularz.

{ "data": {
    "id": "78132d76-…", "projectId": "ff315ea1-…", "schemaId": "d6aea4da-…",
    "formType": "custom", "schemaType": "default",
    "schemaName": { "pl": "Formularz aplikacyjny" },
    "version": "2026-04-09T12:55:57+00:00",
    "isEmailRequired": true, "isPhoneNumberRequired": true, "isCvRequired": true,
    "consents": [                            // ◆ v1.4: zgody RODO projektu
      { "hash": "9f8e7d6c…", "type": "recruitmentProcess",
        "name": "Zgoda na rekrutację",
        "content": "Wyrażam zgodę na przetwarzanie moich danych…",
        "required": true, "allowsCommunication": false },
      { "hash": "1a2b3c4d…", "type": "futureRecruitmentProcess",
        "name": "Zgoda na przyszłe rekrutacje",
        "content": "Wyrażam zgodę na przetwarzanie moich danych również…",
        "required": false, "allowsCommunication": true } ],
    "sections": [
      { "id": "1f0d3c8a-…", "name": { "pl": "Dane podstawowe" }, "order": 0,
        "questions": [
          { "id": "9a2c7e44-…", "type": "oneAnswer", "subtype": null,
            "label": { "pl": "Forma zatrudnienia" }, "isRequired": true, "order": 0,
            "answers": [
              { "id": "b7e1d2a3-…", "content": { "pl": "Umowa o pracę" },
                "isDisqualifying": false, "order": 0 } ] } ],
        "subFormIds": ["30c5a856-…"],
        "subForms": [                          // ◆ v1.2: rozwinięte
          { "id": "30c5a856-…", "type": "week-days",
            "name": { "pl": "W jakich dniach możesz się spotkać?" },
            "sections": [
              { "id": "c1c4ae4c-…", "name": { "pl": "pn." }, "order": 0,
                "questions": [
                  { "id": "4a793138-…", "type": "yesNo", "subtype": "weekDay",
                    "label": { "pl": "pn." }, "isRequired": false, "order": 0 },
                  { "id": "499a4fed-…", "type": "oneAnswer", "subtype": "hourFrom",
                    "label": { "pl": "Od godziny" } } ],
                "subFormIds": [], "subForms": [] } ] } ] } ] } }

Pola sekcji: id, name, description, payload, order, questions[], subFormIds[], subForms[].

Obiekt podformularza (subForms[]): id (zgodny z pozycją w subFormIds sekcji-rodzica), type (np. calendar-days, week-days), name (mapa lokalizacji), sections[] (ta sama struktura co sekcje najwyższego poziomu — rekurencyjnie z questions, subFormIds, subForms).

Obiekt pytania: id (klucz w mapie answers dla POST /apply), type (oneAnswer, multiAnswers, scale, yesNo, open, financialRequirements, languages, file, referral, …), subtype (np. calendarDay, weekDay, hourFrom, hourTo), label, isRequired, order, answers[] (warianty: id — wartość dla oneAnswer/multiAnswerscontent, isDisqualifying, order).

Błędy: 401, 404 project_not_found, 404 application_form_not_found, 429.

8.7 — Wypełniony formularz kandydata

GET/projects/{projectId}/candidates/{candidateId}/application-form?locale={code}

Zwraca wypełniony formularz danego kandydata — sekcje z pytaniami i przesłanymi odpowiedziami.

{ "data": { "projectId": "ff315ea1-…", "candidateId": "87c42b09-…",
    "applicationFormId": "78132d76-…", "submittedAt": "2026-05-27T17:57:48+00:00",
    "formVersion": "2026-04-09T12:55:57+00:00", "locale": "pl",
    "sections": [
      { "title": "Pytania aplikacyjne", "items": [
        { "questionId": "ae8a8a8a-…", "label": "Ocena PHP",
          "type": "scale", "subtype": null, "answer": "1" } ] } ] } }

items[].answer zależy od type (string | int | bool | tablica | null = brak odpowiedzi). Wewnętrzny scoring (obtainedScore, isDisqualified) oraz pytania plikowe są celowo pominięte.

Błędy: 401, 404 project_not_found, 404 application_form_not_found, 429.

8.8 — Profil kandydata

GET/candidates/{candidateId}

Pełny profil (kontakt, doświadczenie, edukacja, umiejętności, języki, certyfikaty). Pola m.in. experience[], education[], skills[], languageSkills[] (cefrLevel A1–C2), certifications[]. Wewnętrzny description CRM jest wykluczony.

Błędy: 401, 404 candidate_not_found, 429.

8.9 — Projekty kandydata

GET/candidates/{candidateId}/projects?page={n}

Stronicowana lista aktywnych projektów, w których uczestniczy kandydat (malejąco po dacie dodania).

Błędy: 401, 404 candidate_not_found, 429.

8.10 — Publiczne notatki kandydata

GET/candidates/{candidateId}/notes?page={n}&projectId={uuid}

Stronicowana lista publicznych notatek. Notatki prywatne nigdy nie są ujawniane. Opcjonalny projectId zawęża do kontekstu projektu. Pola: id, content, createdAt, createdBy, projectId (lub null).

Błędy: 401, 404 candidate_not_found, 429.

8.11 — Aplikacja (utworzenie kandydata) ZMIANA v1.4

POST/projects/{projectId}/apply

Tworzy nowego kandydata i dodaje go do projektu na etapie aplikacyjnym.

⚠ Brak deduplikacji

Każde wywołanie tworzy nowego kandydata — API nie deduplikuje po e-mailu. Aby uniknąć duplikatów, sprawdź najpierw /projects/{id}/candidates. Aplikując bez e-maila (dozwolone od v1.3), tracisz też możliwość deduplikacji po adresie — rozważ własny klucz idempotencji.

Content-Type: multipart/form-data (z plikami) lub application/x-www-form-urlencoded (bez plików).

PoleWym.TypLimitOpis
firstNametakstring255Imię
lastNametakstring255Nazwisko
emailniestring255v1.3E-mail — od v1.3 opcjonalny; jeśli podany, jest walidowany (błędny format → 400 validation_failed). Pominięcie pola tworzy kandydata bez adresu e-mail.
phoneNumberniestring32Telefon (dowolny format)
sourceniestring64Identyfikator źródła; domyślnie external-api
cvniefile5 MBCV kandydata. Zapisywane jako dokument CV.
attachments[]niefile[]3 × 5 MBv1.2Do 3 dodatkowych plików (poza CV), wysyłanych jako powtarzane części multipart attachments[]. Te same dozwolone typy/rozmiar co cv. Każdy zapisywany jako dokument kandydata „Inne".
answersniestring (JSON)Mapa {questionId: wartość} zakodowana jako JSON. Pomiń, by aplikować bez odpowiedzi.
versionwarunk.stringWymagane gdy podano answers. Wartość z pola version w GET …/application-form; niezgodność → 409 stale_form_version.
consents[]niestring[]v1.4Hashe zgód zaakceptowanych przez kandydata — wartości consents[].hash z GET …/application-form, wysyłane jako powtarzane części consents[]. Hash spoza definicji projektu → 400 invalid_consents. Pomiń pole całkowicie, by aplikować bez rejestrowania zgód (dotychczasowe zachowanie).
answerFiles[<questionId>][]niefile[]10 × 5 MBv1.4Pliki jako odpowiedzi na pytania plikowe formularza — mapa kluczowana id pytania (top-level file oraz podformularzowe fileCv/fileOther/filesCollection z GET …/application-form). Pytania jednoplikowe przyjmują dokładnie 1 plik; filesCollection — wiele. Maks. 10 plików łącznie; typy/rozmiar/antywirus jak cv/attachments. Błędne mapowanie → 400 invalid_answer_files.

Mapowanie wartości answers wg typu pytania:

Typ pytaniaWartość w answers
open, yesNo, oneAnswerstring (dla oneAnswerid wariantu odpowiedzi)
scaleinteger
financialRequirementsnumber
multiAnswerstablica id wariantów [id1, id2, …]
calendarDay (subtype; podformularz calendar-days)v1.2data jako string YYYY-MM-DD (np. 2026-06-30)
file (oraz fileCv / fileOther / filesCollection)v1.4niedozwolone w answers — pliki do tych pytań prześlesz przez answerFiles[<questionId>][]
languages, referralniedozwolone — pomiń te pytania w answers

Odpowiedź 201:

{ "candidateId": "4b257ea8-…", "projectId": "ff315ea1-…",
  "answerSheetId": "3c9b1f7e-…" }   // answerSheetId tylko gdy podano poprawne answers; inaczej null
◆ v1.4 — zgody RODO: semantyka
  • Treść zgody prezentujesz Ty. Przed zebraniem akceptacji pokaż kandydatowi dokładną treść content z GET …/application-form. Treści nie przekazujesz w żądaniu — system sam zapisuje snapshot treści z definicji projektu w momencie akceptacji (tak samo jak formularz webowy).
  • Flaga required jest informacyjna. API nie odrzuci aplikacji bez zgody oznaczonej jako wymagana — odpowiedzialność za prezentację i zebranie zgód leży po stronie systemu integratora. Walidacja jest wyłącznie techniczna: nieznany hash → 400 invalid_consents.
  • Skutki zapisu. Zaakceptowane zgody są widoczne w zakładce RODO profilu kandydata, a kandydat wchodzi w filtry „ze zgodą" i podlega śledzeniu ważności zgody. Kandydat przyjęty bez zgód nie pojawia się w filtrach „ze zgodą" i podlega obsłudze anonimizacyjnej przewidzianej dla braku ważnej zgody.
◆ v1.4 — pliki jako odpowiedzi (answerFiles): semantyka
  • Każdy plik jest zapisywany jako dokument kandydata „Inne", a odpowiadające pytanie oznaczane w arkuszu odpowiedzi jako udzielone (Yes) — w podglądzie formularza rekruter widzi pliki z etykietą pytania.
  • Oznaczenie pytania w arkuszu następuje tylko gdy przesłano również answers (z version). answerFiles bez answers nadal zapisuje dokumenty kandydata, ale arkusz odpowiedzi nie powstaje (answerSheetId: null).
  • Ograniczenie (parytet z formularzem webowym): honorowane są pytania plikowe z pierwszej sekcji formularza zawierającej podformularz plikowy; pytania plikowe z ewentualnych kolejnych sekcji z podformularzem plikowym są odrzucane jako nieznane questionId.
◆ v1.4 — automatyczne wiadomości do kandydata

Aplikacja złożona przez API wyzwala teraz to samo zdarzenie aplikacji co formularz webowy — kandydat otrzyma automatyczne wiadomości skonfigurowane w tenancie (np. podziękowanie za aplikację, akcje etapu aplikacyjnego). Wcześniej aplikacje z API nie uruchamiały tych wiadomości. Bez zmian w kontrakcie żądania i odpowiedzi; dotyczy aplikacji złożonych po wdrożeniu v1.4.

◆ v1.3 — dane podstawowe widoczne w podglądzie formularza

Imię, nazwisko, e-mail i telefon przekazane w POST /apply są zapisywane także w arkuszu odpowiedzi — rekruter widzi je w podglądzie formularza kandydata w Element (wcześniej sekcja danych podstawowych była w podglądzie pusta dla aplikacji z API). Kontrakt żądania i odpowiedzi pozostaje bez zmian. Dotyczy aplikacji złożonych po wdrożeniu v1.3 — wcześniejsze arkusze nie są uzupełniane wstecznie.

Przykład (kontakt + CV + załączniki + odpowiedzi + zgody + plik do pytania):

curl --user "api+voicebot@acme.local:<hasło>" \
  -F "firstName=Anna" -F "lastName=Nowak" -F "email=anna.nowak@example.com" \
  -F "source=voicebot-inbound" \
  -F "cv=@./cv.pdf" \
  -F "attachments[]=@./portfolio.pdf" -F "attachments[]=@./certyfikat.png" \
  -F 'version=2026-04-09T12:55:57+00:00' \
  -F 'answers={"9a2c7e44-…":"b7e1d2a3-…","cal-day-q-id":"2026-06-30"}' \
  -F "consents[]=9f8e7d6c…" -F "consents[]=1a2b3c4d…" \
  -F "answerFiles[3fa85f64-…][]=@./referencje.pdf" \
  https://acme.elementapp.ai/api/v1-beta/projects/ff315ea1-…/apply

Przykład minimalny (bez e-maila, od v1.3):

curl --user "api+voicebot@acme.local:<hasło>" \
  -F "firstName=Anna" -F "lastName=Nowak" -F "phoneNumber=+48 500 100 200" \
  https://acme.elementapp.ai/api/v1-beta/projects/ff315ea1-…/apply

Błędy: 400 validation_failed, 400 invalid_answers, 400 invalid_consents, 400 invalid_answer_files, 401, 404 project_not_found, 409 no_application_stage, 409 stale_form_version, 429.

8.12 — Dodanie notatki do kandydata

POST/candidates/{candidateId}/notes

Dodaje publiczną notatkę (autor: konto API, w UI jako API: <nazwa-systemu>). Content-Type: application/x-www-form-urlencoded. Pola: content (wymagane, do 10 000 znaków), projectId (opcjonalne). Odpowiedź 201: { "noteId": "…" }.

Błędy: 400 validation_failed, 401, 404 candidate_not_found, 429.

9Scenariusze integracji

9.1 — Voice-bot: zgłoszenie aplikacji

Bot dzwoni do kandydata, zbiera dane, odczytuje treści zgód RODO pobrane z GET …/application-form i rejestruje akceptację (consents[]), składa aplikację (kontakt + CV) i dodaje transkrypcję jako notatkę.

9.2 — Partner ATS: synchronizacja statusów

ATS cyklicznie pobiera statusy kandydatów w projektach; zachowaj odstęp ≥1 s między wywołaniami (limit 70/min).

9.3 — Pipeline danych: eksport odpowiedzi

System analityczny pobiera listę kandydatów, a dla każdego wypełniony formularz (z parametrem locale); odstęp ≥1 s.

10Bezpieczeństwo i higiena

  • Poświadczenia: jeden zestaw na system; hasło w sejfie sekretów; nigdy w repo/czacie; rotacja przez „Wygeneruj nowe hasło" (stare unieważniane natychmiast).
  • Idempotencja (po stronie integratora): API nie deduplikuje POST /apply. Strategie: sprawdź kandydatów po e-mailu przed wysłaniem (jeśli go zbierasz — od v1.3 e-mail jest opcjonalny), loguj candidateId przed oznaczeniem operacji jako zakończonej, lub użyj wzorca outbox z kluczem idempotencji.
  • Backoff: wykładniczy od 1 s (limit 30 s) na 429; rozkładaj operacje wsadowe w czasie; unikaj równoległych żądań na jednym poświadczeniu.
  • RODO/GDPR: dane kandydatów to dane osobowe (obowiązki po Twojej stronie). Element zwraca 404 candidate_not_found dla kandydatów usuniętych RODO — usuń też swoją kopię.

11Słownik

  • Tenant — klient Element (firma); identyfikowany po subdomenie; poświadczenia zablokowane do jednego tenanta.
  • Projekt — proces rekrutacyjny na jedno stanowisko; ma listę etapów.
  • Etap — krok rekrutacji (Aplikacja, Rozmowa, Oferta…). Etap aplikacyjny (isApplicationType: true) — miejsce lądowania nowych zgłoszeń, max jeden na projekt.
  • Kandydat — osoba w CRM Element; może uczestniczyć w wielu projektach.
  • Podformularz (sub-form) — zagnieżdżony blok pytań w sekcji (np. calendar-days, week-days). Od v1.2 zwracany rozwinięty w subForms[].
  • Zgoda RODO (consent) — definicja zgody na przetwarzanie danych zdefiniowana w projekcie; identyfikowana przez hash (wersję treści). Typy m.in. recruitmentProcess (ta rekrutacja) i futureRecruitmentProcess (przyszłe procesy). Od v1.4 zwracana w GET …/application-form i przyjmowana w POST /apply.
  • Notatka publiczna / prywatna — publiczne widoczne dla konsultantów tenanta i dostępne przez API; prywatne nigdy nie eksponowane.
  • RODO / zapomniany — kandydat zażądał usunięcia danych; zwraca 404.

12Zakres i roadmapa

Dostępne w v1-beta. Odczyt: projekty, etapy, kandydaci w projekcie, pełny schemat formularza (z rozwiniętymi podformularzami i definicjami zgód RODO), wypełnione odpowiedzi kandydata, profil kandydata, projekty kandydata, publiczne notatki. Zapis: zgłoszenie aplikacji (nowy kandydat; wymagane tylko imię i nazwisko — e-mail, telefon, CV, załączniki, odpowiedzi, zgody RODO i pliki do pytań plikowych opcjonalne), publiczna notatka.

Planowane (po v1-beta). Zmiana etapu kandydata, odrzucenie, aktualizacja scoringu, dodanie istniejącego kandydata do projektu, utworzenie projektu.

Celowo pominięte. Notatki prywatne (odczyt/zapis), wewnętrzny description CRM, wewnętrzne pola scoringu (obtainedScore, isDisqualified), odpowiedzi na pytania typu referral/languages w POST /apply (pytania plikowe od v1.4 obsługiwane przez answerFiles), deduplikacja kandydatów przy POST /apply.

◆ Polityka beta

Kontrakt może zmienić się niekompatybilnie w trakcie bety (~2–3 mies. użycia produkcyjnego); zmiany łamiące komunikowane z wyprzedzeniem. Dodatki minorowe (nowe opcjonalne pola, endpointy, kody błędów) nie są łamiące — Twój klient HTTP powinien tolerować dodatkowe pola.

13Kontakt i wsparcie

Zgłoszenia przez standardowy kanał wsparcia Element. Dołącz: subdomenę, login API, znacznik czasu UTC wywołania, metodę + ścieżkę, status HTTP, treść błędu (przynajmniej error.code i error.message) oraz własny identyfikator korelacji. Te dane pozwalają szybko odnaleźć żądanie w logu audytowym.