Wersja API
v1-beta
Wersja dokumentu
1.0 (2026-05-28)
Status
Beta — kontrakt może podlegać zmianom przez okres testów produkcyjnych (~2–3 miesiące).
Odbiorca
Zespół deweloperski po stronie tenanta lub jego partnera technologicznego.
Kontakt techniczny
Standardowy kanał wsparcia Element.

1. O API

Element External Integration API to interfejs REST udostępniający dane i operacje rekrutacyjne z Twojego konta Element systemom zewnętrznym. Pozwala m.in. na:

API zostało zaprojektowane jako uniwersalny mechanizm — ten sam kontrakt obsługuje voice botty, systemy ATS/HRIS partnerów, automatyzacje wewnętrzne i przepływy danych. Wszystkie operacje są audytowane po stronie Element, a autor zmian widoczny jest w panelu jako konto API zidentyfikowane nazwą Twojego systemu (np. API: voicebot).

Charakterystyka

2. Przed startem

Aby skorzystać z API, potrzebujesz:

  1. Aktywnego konta Element Twojej organizacji.
  2. Uprawnień administratora (administrator tenanta) — lub przekazania tego dokumentu osobie posiadającej te uprawnienia.
  3. Dostępu do panelu Element na Twojej subdomenie (https://<twoj-tenant>.elementapp.ai).
  4. Wygenerowanego zestawu credentials dla każdego systemu, który będzie korzystał z API (sekcja Dostęp do API w panelu).

Każdy system zewnętrzny (np. voice bot, system kadrowy) powinien otrzymać osobny zestaw credentials — ułatwia to audyt, ograniczenie blast radius w razie wycieku i niezależną rotację haseł.

Co dostajesz przy tworzeniu credentials

Po utworzeniu w panelu otrzymujesz:

!

Hasło nie jest możliwe do odzyskania. Zapisz je w bezpiecznym miejscu (vault, sejf sekretów, GitHub/GitLab Secrets) od razu po utworzeniu. Jeśli zgubisz hasło, wygeneruj nowe przyciskiem Regeneruj hasło w panelu — poprzednie zostanie unieważnione natychmiast.

3. Pierwsze wywołanie

Po wygenerowaniu credentials zweryfikuj połączenie:

curl --user "api+voicebot@acme.local:<twoje-haslo>" \
     https://acme.elementapp.ai/api/v1-beta/health

Oczekiwana odpowiedź:

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

Jeśli widzisz HTTP 401, sprawdź czy:

4. Uwierzytelnianie

API używa HTTP Basic Authentication zgodnie z RFC 7617.

ElementWartość
SchematBasic
RealmExternal Integration API
UsernameTwój login API
PasswordHasło wygenerowane w panelu
NagłówekAuthorization: Basic base64(login:hasło)

Identyfikacja tenanta

Tenant jest identyfikowany wyłącznie na podstawie subdomeny w URL (acme.elementapp.ai → tenant acme). Credentials są zlocked do jednego tenanta — próba użycia ich na cudzej subdomenie zwróci 401 Unauthorized lub 403 Forbidden.

Konto API w panelu

Twoje konto API jest widoczne w panelu Element jako:

Wszystkie akcje zapisu wykonane przez API są podpisywane Twoim kontem (API: <nazwa-systemu>) — konsultanci tenanta widzą jasno, że dana aplikacja czy notatka pochodzi z systemu zewnętrznego.

5. Format danych

5.1. Content negotiation

5.2. Envelope odpowiedzi

Sukces zwraca obiekt z polem data:

{
  "data": { /* obiekt lub tablica encji */ },
  "meta": { /* obecne tylko dla list paginowanych */ }
}

Błąd zwraca obiekt z polem error:

{
  "error": {
    "code": "snake_case_identifier",
    "message": "Human-readable description (English)."
  }
}

Dla walidacji (HTTP 400) blok error zawiera dodatkowo mapę problemów per pole:

{
  "error": {
    "code": "validation_failed",
    "fields": {
      "email": [
        { "message": "Ta wartość nie jest prawidłowym adresem email.", "code": "bd79c0ab-ddba-46cc-a703-a7a4b08de310" }
      ]
    }
  }
}

Komunikaty walidacji są lokalizowane (w języku domyślnym Twojego tenanta). Identyfikatory pól JSON pozostają w angielskim — to kontrakt API, język niezależny.

5.3. Paginacja

Endpointy zwracające listy przyjmują parametry query:

ParametrTypDomyślnieZakresOpis
pageinteger1≥ 1Numer strony, indeksowany od 1.
perPageinteger201 – 100Liczba elementów na stronie. Wartości spoza zakresu są przycinane.

Każda odpowiedź zawiera blok meta:

{
  "data": [ /* ... */ ],
  "meta": { "page": 1, "perPage": 20, "total": 42 }
}

5.4. Daty i czas

Format ISO 8601 z offsetem UTC: 2026-05-28T12:34:56+00:00. Daty bez czasu (np. okresy zatrudnienia w profilu kandydata) używają formatu YYYY-MM-DD.

5.5. Identyfikatory

Wszystkie identyfikatory zasobów (projectId, candidateId, stageId, noteId, …) to UUID v4 w formacie kanonicznym, np. ff315ea1-c056-472d-aefe-b99f3d41e5c0.

5.6. Lokalizacja treści

Etykiety pytań i wartości wyborów w endpoincie zwracającym wypełniony formularz aplikacyjny (GET /projects/{projectId}/candidates/{candidateId}/application-form) honorują query param locale (np. pl, en, de). Jeśli żądany język nie jest skonfigurowany w formularzu, zwracana jest wartość w domyślnym języku formularza.

6. Limity wywołań

ParametrWartość
Limit domyślny70 wywołań / minutę per credential (60 baseline + 10 burst)
Sustained throughput~1.2 wywołania / sekundę
Klucz limituTwoje konto API

Po przekroczeniu limitu API odpowiada 429 Too Many Requests:

{ "error": { "code": "rate_limit_exceeded", "message": "Too Many Requests" } }

Zalecenia

7. Obsługa błędów

HTTPerror.codeZnaczenie
200 OKSukces (GET).
201 CreatedSukces (POST, zasób utworzony — odpowiedź zawiera identyfikator).
400 Bad Requestvalidation_failedNieprawidłowy lub niepełny request. error.fields opisuje problemy per pole.
401 UnauthorizedBrak nagłówka Authorization, nieprawidłowy login lub hasło. Body puste, nagłówek WWW-Authenticate: Basic.
403 ForbiddenKonto bez wymaganej roli lub dezaktywowane. Body puste.
404 Not Foundproject_not_foundProjekt nie istnieje, jest zarchiwizowany lub nie należy do Twojego tenanta.
404 Not Foundcandidate_not_foundKandydat nie istnieje, jest zarchiwizowany, nie należy do Twojego tenanta lub zażądał usunięcia danych (RODO).
404 Not Foundapplication_form_not_foundProjekt nie ma podpiętego formularza aplikacyjnego lub kandydat nie wypełnił go w tym projekcie.
409 Conflictno_application_stagePOST /apply: projekt nie ma skonfigurowanego etapu typu „aplikacja".
429 Too Many Requestsrate_limit_exceededPrzekroczony limit (sekcja 6).
5xxAwaria po stronie Element. Spróbuj ponownie z backoff. Jeśli powtarza się dłużej niż kilka minut, skontaktuj się z supportem.

8. Referencja endpointów

Wszystkie endpointy poprzedzone są base URL: https://<twoj-tenant>.elementapp.ai/api/v1-beta.

8.1. Health check

GET/health

Weryfikacja dostępności API i poprawności credentials. Nie zwraca danych biznesowych.

Odpowiedź 200:

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

8.2. Lista projektów

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

Zwraca paginowaną listę aktywnych projektów rekrutacyjnych Twojego tenanta.

Odpowiedź 200:

{
  "data": [
    {
      "id": "ff315ea1-c056-472d-aefe-b99f3d41e5c0",
      "name": "Senior PHP Developer",
      "positionName": null,
      "isRemote": true,
      "statusId": "73f09ef2-77f7-4b12-bbed-5beb6131dbea",
      "createdAt": "2021-10-31T11:42:24+00:00"
    }
  ],
  "meta": { "page": 1, "perPage": 20, "total": 8 }
}
PoleTypOpis
idUUIDIdentyfikator projektu — używaj go w pozostałych endpointach.
namestringNazwa projektu.
positionNamestring | nullTytuł stanowiska, jeśli różny od nazwy projektu.
isRemoteboolCzy stanowisko jest zdalne.
statusIdUUIDIdentyfikator statusu projektu.
createdAtdatetimeData utworzenia projektu.

8.3. Szczegóły projektu

GET/projects/{projectId}

Zwraca pełne dane projektu wraz z listą etapów.

Odpowiedź 200:

{
  "data": {
    "id": "ff315ea1-c056-472d-aefe-b99f3d41e5c0",
    "name": "Senior PHP Developer",
    "positionName": null,
    "isRemote": true,
    "statusId": "73f09ef2-77f7-4b12-bbed-5beb6131dbea",
    "createdAt": "2021-10-31T11:42:24+00:00",
    "responsibilities": "<ul><li>...</li></ul>",
    "requirements": "<ul><li>...</li></ul>",
    "offer": "<ul><li>...</li></ul>",
    "minimumSalary": 12000,
    "maximumSalary": 18000,
    "numberOfVacancies": 4,
    "stages": [
      { "id": "...", "name": "Linkedin — zaproszeni", "isApplicationType": false },
      { "id": "...", "name": "Aplikacja",             "isApplicationType": true  },
      { "id": "...", "name": "Rozmowa",               "isApplicationType": false }
    ]
  }
}
PoleTypOpis
responsibilities, requirements, offerstring HTML | nullTreści marketingowe — mogą zawierać tagi HTML (<ul>, <li>, <p>, …).
minimumSalary, maximumSalaryint | nullWidełki wynagrodzenia w walucie konfigurowanej w tenancie. 0 oznacza „nie ustawione".
numberOfVacanciesint | nullLiczba wakatów.
stagesarrayLista etapów rekrutacji w projekcie.
stages[].isApplicationTypebooltrue dla etapu, w którym lądują aplikacje z POST /apply.

Możliwe błędy: 401, 404 project_not_found, 429.

8.4. Etapy projektu

GET/projects/{projectId}/stages

Skrócona wersja — tylko lista etapów (ten sam shape co data.stages z /projects/{projectId}).

{
  "data": [
    { "id": "515806af-0470-40ef-84ed-4ce889d103ed", "name": "Aplikacja", "isApplicationType": true },
    { "id": "0f23ea11-fa6d-42b6-97c2-8356e8d1827e", "name": "Rozmowa",   "isApplicationType": false }
  ]
}

Możliwe błędy: 401, 404 project_not_found, 429.

8.5. Kandydaci w projekcie

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

Paginowana lista kandydatów uczestniczących w projekcie. Opcjonalnie filtruj po etapie.

{
  "data": [
    {
      "id": "87c42b09-4cde-47db-90f9-963928fedbdb",
      "firstName": "Anna",
      "lastName": "Nowak",
      "email": "anna.nowak@example.com",
      "stageId": "515806af-0470-40ef-84ed-4ce889d103ed",
      "isRejected": false,
      "addedAt": "2026-05-27T17:57:52+00:00"
    }
  ],
  "meta": { "page": 1, "perPage": 20, "total": 17 }
}
PoleTypOpis
idUUIDIdentyfikator kandydata.
firstName, lastNamestring | nullImię i nazwisko.
emailstringEmail ("" możliwe dla kandydatów zaimportowanych historycznie).
stageIdUUIDAktualny etap kandydata w tym projekcie.
isRejectedboolCzy kandydat został odrzucony w tym projekcie.
addedAtdatetimeData dodania do projektu.

Możliwe błędy: 401, 404 project_not_found, 429.

8.6. Metadane formularza aplikacyjnego projektu

GET/projects/{projectId}/application-form

Zwraca metadane formularza aplikacyjnego podpiętego do projektu — bez treści pytań.

{
  "data": {
    "id": "78132d76-ec2e-4fb4-a069-8688b9c4d2e2",
    "projectId": "ff315ea1-c056-472d-aefe-b99f3d41e5c0",
    "schemaId": "d6aea4da-b701-4504-aaa7-58062c302493",
    "type": "custom",
    "isEmailRequired": true,
    "isPhoneNumberRequired": true,
    "isCvRequired": true
  }
}
PoleTypOpis
idUUIDIdentyfikator instancji formularza.
schemaIdUUIDIdentyfikator wersji schematu (zmiana = nowa wersja pytań).
typestring"custom", "default", "signal".
isEmailRequired, isPhoneNumberRequired, isCvRequiredboolCzy pole jest wymagane. Użyj do walidacji przed wysłaniem POST /apply.
i

Pełna struktura formularza (pytania, opcje, walidacje) jest świadomie pomijana w v1-beta — zewnętrzne systemy mają używać własnego flow do zbierania danych i wywołać POST /apply z minimalnym zestawem (patrz 8.11).

Możliwe błędy: 401, 404 project_not_found, 404 application_form_not_found, 429.

8.7. Odpowiedzi kandydata w formularzu

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

Zwraca wypełniony formularz aplikacyjny konkretnego kandydata w konkretnym projekcie — każdą sekcję wraz z pytaniami i odpowiedziami.

{
  "data": {
    "projectId": "ff315ea1-c056-472d-aefe-b99f3d41e5c0",
    "candidateId": "87c42b09-4cde-47db-90f9-963928fedbdb",
    "applicationFormId": "78132d76-ec2e-4fb4-a069-8688b9c4d2e2",
    "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-c8c2-48d3-9e2d-b3c6ba7f2a35",
            "label": "Jak oceniasz swoją umiejętność programowania w PHP?",
            "type": "scale",
            "subtype": null,
            "answer": "1"
          },
          {
            "questionId": "15a281d6-0923-4a57-bf22-4e82622e324c",
            "label": "Osoba polecająca",
            "type": "referral",
            "subtype": null,
            "answer": { "name": null, "email": null, "surname": null }
          }
        ]
      }
    ]
  }
}
PoleTypOpis
applicationFormIdUUIDIdentyfikator wersji formularza w momencie złożenia.
submittedAtdatetimeKiedy kandydat złożył aplikację.
formVersiondatetimeSygnatura czasowa wersji schematu pytań.
localestringFaktycznie zwrócony język (po ewentualnym fallbacku).
sections[].items[].typestringoneAnswer, manyAnswers, scale, yesNo, text, number, date, referral, …
sections[].items[].subtypestring | nullDodatkowy kontekst semantyczny (weekDay, hourFrom, hourTo, …).
sections[].items[].answerstring | int | bool | array | nullOdpowiedź; typ zależy od type/subtype. null = brak odpowiedzi.
i

Pomijane celowo:

  • Wewnętrzny scoring kandydata (obtainedScore, isDisqualified) — to mechanizm wewnętrzny Element.
  • Pytania typu „upload pliku" — jeśli sekcja zawiera wyłącznie pytania plikowe, jest pomijana w odpowiedzi.

Możliwe błędy: 401, 404 project_not_found, 404 application_form_not_found, 429.

8.8. Profil kandydata

GET/candidates/{candidateId}

Zwraca pełen profil kandydata.

{
  "data": {
    "id": "87c42b09-4cde-47db-90f9-963928fedbdb",
    "firstName": "Anna",
    "lastName": "Nowak",
    "email": "anna.nowak@example.com",
    "phoneNumber": "+48500111222",
    "financialExpectation": 12000,
    "optimalFinancialExpectation": 15000,
    "isRemote": false,
    "createdAt": "2026-05-27T17:57:48+00:00",
    "experience": [
      {
        "companyName": "Acme Sp. z o.o.",
        "jobPosition": "Senior PHP Developer",
        "description": "Architektura mikroserwisów, …",
        "employedSince": "2020-01-01",
        "employedTo": null
      }
    ],
    "education": [
      {
        "educationFacility": "Politechnika Warszawska",
        "specialization": "Informatyka",
        "attendedSince": "2014-10-01",
        "attendedTo": "2019-06-30"
      }
    ],
    "skills": [
      { "name": "PHP", "experienceInYears": 8 }
    ],
    "languageSkills": [
      { "languageId": "en", "cefrLevel": "C1" }
    ],
    "certifications": [
      { "certificationId": "...", "name": "AWS Certified Developer" }
    ]
  }
}
PoleTypOpis
firstName, lastNamestring | nullImię i nazwisko.
email, phoneNumberstring | nullDane kontaktowe.
financialExpectation, optimalFinancialExpectationint | nullMinimalne / oczekiwane wynagrodzenie w walucie tenanta.
isRemoteboolCzy kandydat preferuje pracę zdalną.
experience[]arrayDoświadczenie zawodowe (daty YYYY-MM-DD, employedTo: null = nadal zatrudniony).
education[]arrayWykształcenie.
skills[].experienceInYearsintLata doświadczenia z daną umiejętnością.
languageSkills[].cefrLevelstringPoziom CEFR (A1C2).

Wewnętrzny opis konsultanta (pole description w CRM Element) jest świadomie wyłączony z odpowiedzi — to prywatne notatki rekruterów, nie podlegają udostępnianiu przez API.

Możliwe błędy: 401, 404 candidate_not_found, 429.

8.9. Projekty kandydata

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

Paginowana lista aktywnych projektów, w których kandydat bierze udział, posortowana po dacie dodania (malejąco).

{
  "data": [
    {
      "projectId": "ff315ea1-c056-472d-aefe-b99f3d41e5c0",
      "projectName": "Senior PHP Developer",
      "stageId": "515806af-0470-40ef-84ed-4ce889d103ed",
      "isRejected": false,
      "addedAt": "2026-05-27T17:57:52+00:00"
    }
  ],
  "meta": { "page": 1, "perPage": 20, "total": 1 }
}

Możliwe błędy: 401, 404 candidate_not_found, 429.

8.10. Publiczne notatki kandydata

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

Paginowana lista publicznych notatek kandydata. Notatki prywatne nie są nigdy udostępniane przez API.

Parametr queryTypOpis
page, perPageintPaginacja.
projectIdUUIDOpcjonalnie — zawęź do notatek dodanych w kontekście wskazanego projektu.
{
  "data": [
    {
      "id": "898a1822-ac9e-4473-9f56-e0a8542676e7",
      "content": "Kandydat zaakceptował ofertę wstępną.",
      "createdAt": "2026-05-28T08:41:22+00:00",
      "createdBy": "a7a58f75-25b8-462b-813e-0248265603e8",
      "projectId": "ff315ea1-c056-472d-aefe-b99f3d41e5c0"
    }
  ],
  "meta": { "page": 1, "perPage": 20, "total": 1 }
}
PoleTypOpis
createdByUUIDIdentyfikator autora notatki w Element (Twoje konto API albo konto konsultanta).
projectIdUUID | nullnull jeśli notatka jest na profilu kandydata, nie powiązana z projektem.

Możliwe błędy: 401, 404 candidate_not_found, 429.

8.11. Złożenie aplikacji

POST/projects/{projectId}/apply

Tworzy nowego kandydata i dodaje go do projektu na etapie typu „aplikacja".

!

Każde wywołanie tworzy nowego kandydata. API nie deduplikuje po adresie email. Jeśli chcesz uniknąć duplikatów, sprawdź najpierw /projects/{projectId}/candidates po stronie Twojego systemu.

Content-Type: multipart/form-data (z CV) lub application/x-www-form-urlencoded (bez CV).

Pola requestu:

PoleWymaganeTypLimitOpis
firstNametakstring255 znakówImię.
lastNametakstring255 znakówNazwisko.
emailtakstring255 znakówEmail, walidowany.
phoneNumberniestring32 znakiTelefon (format swobodny).
sourceniestring64 znakiIdentyfikator źródła aplikacji w Twoim systemie. Domyślnie external-api.
cvniefile5 MBCV kandydata. Format: PDF, DOC/DOCX, ODT, RTF, TXT, JPG, PNG. Plik skanowany antywirusowo.

Akceptowane typy MIME pliku CV: application/pdf, application/x-pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.oasis.opendocument.text, application/vnd.oasis.opendocument.text-master, application/rtf, text/plain, image/jpeg, image/png.

Odpowiedź 201:

{
  "candidateId": "4b257ea8-5eca-46da-8a26-562c6d78bd2d",
  "projectId": "ff315ea1-c056-472d-aefe-b99f3d41e5c0"
}

Przykład:

curl --user "api+voicebot@acme.local:<haslo>" \
     -F "firstName=Anna" \
     -F "lastName=Nowak" \
     -F "email=anna.nowak@example.com" \
     -F "phoneNumber=+48500111222" \
     -F "source=voicebot-inbound" \
     -F "cv=@./cv.pdf" \
     https://acme.elementapp.ai/api/v1-beta/projects/ff315ea1-c056-472d-aefe-b99f3d41e5c0/apply

Możliwe błędy: 400 validation_failed, 401, 404 project_not_found, 409 no_application_stage, 429.

8.12. Dodanie notatki

POST/candidates/{candidateId}/notes

Dodaje publiczną notatkę do profilu kandydata. Notatki dodane przez API są zawsze publiczne. Autorem jest Twoje konto API — w UI Element widoczne jako API: <nazwa-systemu>.

Content-Type: application/x-www-form-urlencoded.

Pola requestu:

PoleWymaganeTypLimitOpis
contenttakstring10 000 znakówTreść notatki (plain text).
projectIdnieUUIDPowiąż notatkę z konkretnym projektem. Bez projectId notatka jest na ogólnym profilu kandydata.

Odpowiedź 201:

{ "noteId": "898a1822-ac9e-4473-9f56-e0a8542676e7" }

Przykład:

curl --user "api+voicebot@acme.local:<haslo>" \
     --data-urlencode "content=Voice bot — kandydat oddzwoni jutro między 10:00 a 12:00." \
     --data-urlencode "projectId=ff315ea1-c056-472d-aefe-b99f3d41e5c0" \
     https://acme.elementapp.ai/api/v1-beta/candidates/4b257ea8-5eca-46da-8a26-562c6d78bd2d/notes

Możliwe błędy: 400 validation_failed, 401, 404 candidate_not_found, 429.

9. Scenariusze integracji

9.1. Voice bot — przyjęcie aplikacji telefonicznej

Voice bot dzwoni do kandydata, zbiera dane, zapisuje aplikację i notatkę z rozmowy.

BASE="https://acme.elementapp.ai"
AUTH="api+voicebot@acme.local:<haslo>"
PROJECT_ID="ff315ea1-c056-472d-aefe-b99f3d41e5c0"

# 1. (Opcjonalnie) sprawdź wymagane pola formularza
curl --user "$AUTH" "$BASE/api/v1-beta/projects/$PROJECT_ID/application-form"

# 2. Złóż aplikację
RESP=$(curl --user "$AUTH" \
  -F "firstName=Anna" \
  -F "lastName=Nowak" \
  -F "email=anna.nowak@example.com" \
  -F "phoneNumber=+48500111222" \
  -F "source=voicebot" \
  "$BASE/api/v1-beta/projects/$PROJECT_ID/apply")
CANDIDATE_ID=$(echo "$RESP" | jq -r .candidateId)

# 3. Zapisz transkrypcję najważniejszych ustaleń jako notatkę
curl --user "$AUTH" \
  --data-urlencode "content=Voice bot — kandydat potwierdził dostępność od 1 czerwca, oczekiwania 15k netto, otwarty na pracę zdalną." \
  --data-urlencode "projectId=$PROJECT_ID" \
  "$BASE/api/v1-beta/candidates/$CANDIDATE_ID/notes"

9.2. System ATS — synchronizacja statusów kandydatów

System ATS partnera regularnie pobiera status kandydatów w projektach Element, aby zachować spójność widoków.

# Pobierz aktualne projekty
PROJECTS=$(curl --user "$AUTH" "$BASE/api/v1-beta/projects?perPage=100")

# Dla każdego projektu, pobierz kandydatów wraz ze stage
for PROJECT_ID in $(echo "$PROJECTS" | jq -r '.data[].id'); do
  curl --user "$AUTH" "$BASE/api/v1-beta/projects/$PROJECT_ID/candidates?perPage=100"
  sleep 1   # backoff — szanuj limit 70/min
done

9.3. Pipeline danych — eksport odpowiedzi z formularzy

System analityczny pobiera odpowiedzi kandydatów na pytania formularza dla projektu.

PROJECT_ID="ff315ea1-c056-472d-aefe-b99f3d41e5c0"

# 1. Lista kandydatów w projekcie
CANDIDATES=$(curl --user "$AUTH" "$BASE/api/v1-beta/projects/$PROJECT_ID/candidates?perPage=100")

# 2. Dla każdego — pobierz wypełniony formularz
for CANDIDATE_ID in $(echo "$CANDIDATES" | jq -r '.data[].id'); do
  curl --user "$AUTH" "$BASE/api/v1-beta/projects/$PROJECT_ID/candidates/$CANDIDATE_ID/application-form?locale=pl"
  sleep 1
done

10. Bezpieczeństwo i higiena integracji

10.1. Higiena credentials

10.2. Idempotencja po stronie integratora

API nie deduplikuje wywołań. Retry sieciowy po POST /apply utworzy drugiego kandydata. Stosuj jeden z mechanizmów po Twojej stronie:

10.3. Backoff i rate limit

10.4. Logowanie po stronie integratora

Loguj zawsze:

Te dane wraz z timestampem i loginem API pozwolą supportowi Element zlokalizować dokładnie ten request w audit logu po stronie Element w razie problemu.

10.5. Dane wrażliwe

11. Słownik pojęć

PojęcieZnaczenie
TenantKlient Element (np. firma rekrutacyjna). Identyfikowany subdomeną (acme.elementapp.ai). Credentials API są zlocked do jednego tenanta.
ProjektProces rekrutacyjny na jedno stanowisko. Posiada listę etapów.
Etap (stage)Krok w procesie rekrutacyjnym (np. „Aplikacja", „Rozmowa", „Ofertowanie").
Etap typu „aplikacja"isApplicationType: true — etap, w którym lądują nowo zaaplikowani kandydaci. POST /apply zawsze przypisuje nowych kandydatów do tego etapu. Każdy projekt ma co najwyżej jeden taki etap.
KandydatOsoba zarejestrowana w CRM Element. Może uczestniczyć w wielu projektach jednocześnie.
Notatka publicznaNotatka widoczna dla wszystkich konsultantów tenanta. API zawsze tworzy notatki publiczne.
Notatka prywatnaNotatka widoczna tylko dla autora. Niedostępna przez API.
Formularz aplikacyjnyKonfigurowalny zestaw pytań do kandydatów. v1-beta udostępnia metadane formularza projektu oraz odpowiedzi już złożone przez kandydatów.
RODO / forgottenKandydat, który zażądał usunięcia danych osobowych. Zwraca 404 candidate_not_found.

12. Zakres v1-beta i plan rozwoju

12.1. Co jest dostępne w v1-beta

Odczyt (GET): projekty, etapy, kandydaci w projekcie, metadane formularza, wypełniony formularz kandydata, profil kandydata, projekty kandydata, publiczne notatki kandydata.

Zapis (POST): złożenie aplikacji w projekcie (utworzenie kandydata), dodanie publicznej notatki do kandydata.

12.2. Planowane rozszerzenia (poza v1-beta)

Po ustabilizowaniu kontraktu v1-beta i przejściu na v1 planowane jest rozszerzenie API o dodatkowe operacje workflow rekrutacyjnego: zmiana etapu kandydata, odrzucenie kandydata, zmiana oceny, dodanie istniejącego kandydata do projektu, utworzenie projektu.

Zakres i terminy będą komunikowane oddzielnie.

12.3. Świadomie pominięte

12.4. Polityka zmian w okresie beta

i
  • Kontrakt API może podlegać niekompatybilnym zmianom w okresie beta (~2–3 miesiące produkcyjnego użycia).
  • Istotne zmiany będą sygnalizowane z wyprzedzeniem przez zespół Element.
  • Po zakończeniu okresu beta wersja v1-beta zostanie zamrożona jako stabilne v1. Wszelkie kolejne breaking changes pojawią się pod nowym prefiksem (/api/v2/, …).
  • Drobne uzupełnienia kontraktu (nowe opcjonalne pola w odpowiedziach, nowe endpointy, nowe wartości error.code) nie są traktowane jako breaking i mogą pojawiać się również w okresie beta — Twój klient HTTP powinien tolerować dodatkowe pola.

13. Kontakt i wsparcie

W razie problemów technicznych z API:

Te dane pozwolą zlokalizować konkretny request w audit logu Element i przyspieszyć diagnozę.