Logo StartupKit
PL

Dokumentacja API

Uwierzytelnij się i odpytuj API rekrutacyjne, żeby pobrać dane o ogłoszeniach o pracę, kandydatach i aplikacjach.

Dlaczego to ważne

API rekrutacyjne umożliwia systemom zewnętrznym odczyt danych rekrutacyjnych — portale z ofertami pracy pobierają opublikowane ogłoszenia, systemy HRIS synchronizują dane kandydatów, a panele kontrolne śledzą metryki procesu rekrutacji. Zakresy uprawnień tokenu zapewniają, że każda integracja widzi tylko to, czego potrzebuje.

Bazowy URL

Wszystkie endpointy API są dostępne pod adresem:

https://startupkit.app/api/v1

Uwierzytelnianie

Każde żądanie wymaga tokenu API w nagłówku Authorization:

Authorization: Bearer YOUR_TOKEN

Alternatywny format (oba działają):

Authorization: token YOUR_TOKEN

Tokeny można utworzyć w sekcji Settings > API. Każdy token musi mieć jawnie przypisane zakresy uprawnień, aby uzyskać dostęp do endpointów rekrutacyjnych.

Zakres Dostęp
job_postings:read Ogłoszenia o pracę i etapy
candidates:read Dane osobowe kandydatów (imię, e-mail, telefon), pola meta aplikacji, pobieranie CV
applications:read Aplikacje, historia etapów, pobieranie CV

Tokeny bez przypisanych zakresów nie mają dostępu do endpointów rekrutacyjnych.

Format i cykl życia tokenu

  • Format: 24-znakowy ciąg base58 (np. k3Jf9pQ2mZ7xR4nL8vT6bWyH)
  • Pokazywany tylko raz: Surowy token wyświetla się dokładnie raz — na ekranie potwierdzenia zaraz po utworzeniu. Skopiuj go od razu; później nie da się go odzyskać.
  • Przechowywany tylko jako skrót: Kit zapisuje wyłącznie skrót SHA-256 tokenu, nigdy postaci jawnej. Jeśli zgubisz token, unieważnij go i utwórz nowy; pierwotnej wartości nie da się odzyskać.
  • Śledzenie ostatniego użycia: Każde udane żądanie aktualizuje pole last_used_at
  • Brak daty wygaśnięcia: Tokeny nie wygasają po upływie czasu. Formularz tworzenia nie ma opcji wygaśnięcia, a Settings > API nie pokazuje żadnej takiej daty — token pozostaje ważny, dopóki go nie unieważnisz.
  • Alerty o braku aktywności: Tokeny nieużywane przez ponad 30 dni generują powiadomienia dla administratorów
  • Automatyczne unieważnienie: Tokeny są automatycznie unieważniane po usunięciu użytkownika z konta

Zalecana praktyka: twórz osobne tokeny dla każdej integracji z minimalnymi wymaganymi zakresami uprawnień.

Zakres konta

Każdy token API jest powiązany z konkretnym kontem. Konto jest ustalane automatycznie na podstawie tokenu — parametr account_id nie jest wymagany.

Gdy członek zespołu zostanie usunięty z konta, jego tokeny dla tego konta są automatycznie unieważniane.

Odpowiedzi z błędami

Status Znaczenie Najczęstsze przyczyny
400 Nieprawidłowe żądanie Brak kontekstu konta (przypadek brzegowy przy uwierzytelnianiu sesyjnym)
401 Brak autoryzacji Brakujący, nieprawidłowy lub unieważniony token
403 Brak dostępu Token nie ma wymaganego zakresu uprawnień dla tego endpointu
404 Nie znaleziono Zasób nie istnieje lub nie należy do danego konta
422 Błąd walidacji Błędy walidacji (głównie dla endpointów spoza modułu rekrutacji)

Paginacja

Endpointy listowe zwracają wyniki z paginacją:

{
  "data": [...],
  "pagination": {
    "current_page": 1,
    "total_pages": 3,
    "total_count": 42,
    "per_page": 20
  }
}

Przekaż parametr ?page=2, żeby pobrać kolejne strony.


Ogłoszenia o pracę

Wymagany zakres: job_postings:read

Lista ogłoszeń o pracę

GET /api/v1/job_postings

Przykład:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/job_postings?status=published

Parametry:

Parametr Typ Opis
status string Filtrowanie według statusu: draft, published, paused lub closed
page integer Numer strony

Odpowiedź:

{
  "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": { ... }
}

Pobieranie ogłoszenia o pracę

GET /api/v1/job_postings/:id

Zwraca dane w tym samym formacie co pojedynczy element odpowiedzi listowej.

Lista etapów

GET /api/v1/job_postings/:job_posting_id/stages

Odpowiedź:

{
  "data": [
    {
      "id": "stg_def456",
      "name": "Screening",
      "stage_type": "default",
      "position": 0
    }
  ]
}

Etapy są posortowane według pozycji. Bez paginacji.


Kandydaci

Wymagany zakres: candidates:read

Lista kandydatów

GET /api/v1/candidates

Przykład:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/[email protected]

Parametry:

Parametr Typ Opis
search string Wyszukiwanie według imienia, nazwiska lub adresu e-mail
page integer Numer strony

Odpowiedź:

{
  "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": { ... }
}

Pobieranie kandydata

GET /api/v1/candidates/:id

Zwraca dane w tym samym formacie co pojedynczy element odpowiedzi listowej.


Aplikacje

Wymagany zakres: applications:read

Lista aplikacji

GET /api/v1/applications

Przykład:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/applications?job_posting_id=job_abc123&status=active

Parametry:

Parametr Typ Opis
job_posting_id string Filtrowanie według prefiksowego ID ogłoszenia o pracę
status string Filtrowanie według statusu: active lub rejected
page integer Numer strony

Odpowiedź:

{
  "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": { ... }
}

Dane pól meta

Wymagany zakres: candidates:read

Wartości pól meta mogą zawierać dane osobowe kandydata wyodrębnione przez AI, dlatego tablica metafields jest chroniona zakresem candidates:read — tym samym, który chroni blok candidate — a nie zakresem applications:read. Token z zakresem applications:read, ale bez candidates:read, dostaje odpowiedzi o aplikacjach w ogóle bez klucza metafields. Przykładowa odpowiedź powyżej pokazuje to, co widzi token z obydwoma zakresami.

Jeśli token ma zakres candidates:read, każda aplikacja zawiera tablicę metafields z ustrukturyzowanymi polami danych wyodrębnionymi lub wprowadzonymi dla tej aplikacji. Każdy wpis zawiera:

Pole Typ Opis
key string Maszynowy identyfikator pola
label string Czytelna dla człowieka nazwa wyświetlana
field_type string Typ danych — dokładnie jeden z tych dziewięciu: text, textarea, number, date, select, boolean, url, rating, tags
value string | null Bieżąca wartość (zawsze serializowana jako ciąg znaków)
source string Sposób ustawienia wartości — dokładnie jedna z dwóch wartości: manual (wprowadzona lub zmieniona przez człowieka) albo ai (wyodrębniona lub ustawiona przez AI)
confidence float | null Wskaźnik pewności AI (0.0–1.0), gdy source to ai; w przeciwnym razie null
extracted_at timestamp | null Kiedy wartość została ustawiona lub wyodrębniona
edited boolean true tylko wtedy, gdy wartość pochodząca z AI została później nadpisana czymś innym niż surowe wyodrębnienie przez AI (w praktyce wywołaniem MCP hiring_update_metafield_value). Zmiany wprowadzone przez człowieka we własnym interfejsie Kit zapisują source: manual i zawsze zwracają edited: false.
original_value string | null Pierwotna wartość wyodrębniona przez AI przed edycją przez człowieka; null, jeśli nigdy nie edytowano

W obrębie tokenu z zakresem candidates:read tablica metafields nie jest już dodatkowo filtrowana według flagi widoczności managers_only. Każde pole meta zdefiniowane w ogłoszeniu o pracę — w tym pola oznaczone jako managers_only w konfiguracji ogłoszenia — jest zwracane niezależnie od roli właściciela tokenu. Zakres candidates:read jest więc jedynym mechanizmem kontrolującym dostęp do pól meta: jeśli pole zawiera dane wrażliwe, których nie chcesz udostępniać integracji, nie przyznawaj tej integracji zakresu candidates:read, ponieważ API nie stosuje filtrowania widoczności dla menedżerów używanego w innych częściach aplikacji. Sam zakres applications:read jest pod tym względem bezpieczny — zwraca historię etapów i status aplikacji, bez pól meta.

Pobieranie aplikacji

GET /api/v1/applications/:id

Zwraca dane w tym samym formacie co pojedynczy element odpowiedzi listowej. Gdy token ma zakres candidates:read, a do aplikacji dołączono CV, odpowiedź zawiera metadane CV:

{
  "id": "app_jkl012",
  "resume_filename": "john_doe_resume.pdf",
  "resume_content_type": "application/pdf",
  "resume_byte_size": 245760,
  ...
}

Te pola są pomijane, gdy CV nie jest dołączone lub brakuje zakresu candidates:read.

Pobieranie CV

Wymagane zakresy: applications:read + candidates:read

GET /api/v1/applications/:application_id/resume

Pobiera CV kandydata dla wskazanej aplikacji. Zwraca przekierowanie 302 na podpisany URL z ograniczonym czasem ważności (30 minut).

Przykład:

curl -L -H "Authorization: Bearer YOUR_TOKEN" \
  -o resume.pdf \
  https://startupkit.app/api/v1/applications/app_jkl012/resume

Odpowiedź:

  • 302 Found – Przekierowanie na podpisany URL do pobrania. Użyj -L (podążanie za przekierowaniami) w curl.
  • 403 Forbidden – Token nie ma zakresu applications:read lub candidates:read.
  • 404 Not Found – Nie znaleziono aplikacji lub brak dołączonego CV.

Uwagi:

  • Podpisane URL wygasają po 30 minutach. Po wygaśnięciu pobierz nowy.
  • Nagłówek Content-Disposition jest ustawiony na attachment (wymusza pobranie pliku przez przeglądarkę).
  • Obsługiwane formaty CV: PDF, DOC, DOCX (zgodnie z tym, co przesłał kandydat).

Maskowanie danych osobowych kandydata

Gdy token ma zakres applications:read, ale nie ma zakresu candidates:read, dane kandydata w odpowiedziach dotyczących aplikacji są ograniczone wyłącznie do identyfikatora:

{
  "candidate": {
    "id": "cand_ghi789"
  }
}

Pola first_name, last_name ani email nie są uwzględniane. Ta sama zasada obejmuje tablicę metafields oraz pola z metadanymi CV — one również są całkowicie pomijane, bo także mogą zawierać dane osobowe kandydata. Dzięki temu integracje z portalami ofert pracy mogą śledzić status aplikacji bez ujawniania danych kontaktowych kandydatów.


Rozwiązywanie problemów

Problemy z uwierzytelnianiem

401 Unauthorized

Jeśli dostajesz odpowiedź 401, sprawdź:

  1. Format tokenu: Token powinien odpowiadać wartości pokazanej jednorazowo podczas tworzenia (24-znakowy ciąg base58). Jeśli już go nie masz, unieważnij token i utwórz nowy — Kit przechowuje tylko zahaszowany skrót i nie pokaże go ponownie.
  2. Nagłówek Authorization: Musi mieć format Authorization: Bearer TOKEN lub Authorization: token TOKEN
  3. Czy token nadal istnieje: Sprawdź, czy token wciąż jest na liście w Settings > API — unieważniony token zostaje usunięty, a nie wyłączony
  4. Członkostwo w koncie: Upewnij się, że właściciel tokenu nadal jest członkiem konta

403 Forbidden

Gdy dostajesz odpowiedź 403, token jest prawidłowy, ale nie ma wymaganego zakresu uprawnień:

  1. Sprawdź wymagane zakresy: Każdy endpoint dokumentuje wymagany zakres (np. job_postings:read)
  2. Dodaj brakujące zakresy: Edytuj token w Settings > API i dodaj potrzebny zakres
  3. Format zakresu: Musi dokładnie odpowiadać wzorcowi — job_postings:read, a nie job_postings lub read

Problemy z dostępem do danych

Pusta tablica data w odpowiedziach

Jeżeli API zwraca {"data": [], "pagination": {...}}, a spodziewane są wyniki:

  1. Izolacja kont: Tokeny API widzą tylko dane z konta, do którego są przypisane
  2. Weryfikacja konta: Sprawdź, do którego konta należy token w Settings > API
  3. Dostęp między kontami: Tokeny nie mogą uzyskać dostępu do danych z innych kont, nawet jeśli użytkownik jest ich członkiem

Dane osobowe kandydata są zamaskowane

Jeżeli widoczne jest jedynie {"candidate": {"id": "cand_..."}} bez imienia i adresu e-mail:

  1. Oczekiwane zachowanie: Dzieje się tak, gdy token ma zakres applications:read, ale nie ma zakresu candidates:read
  2. Dodaj zakres: Żeby zobaczyć pełne dane kandydata, dodaj zakres candidates:read do tokenu
  3. Ochrona prywatności: Dzięki temu integracje mogą śledzić aplikacje bez ujawniania danych kontaktowych

Brak tablicy metafields w odpowiedziach o aplikacjach

Tablica metafields jest chroniona zakresem candidates:read, a nie applications:read, bo wartości pól meta mogą zawierać dane osobowe kandydata wyodrębnione przez AI. Jeśli w odpowiedziach nie ma klucza metafields, token nie ma zakresu candidates:read. Dodaj go tylko wtedy, gdy integracja ma widzieć również imiona i nazwiska kandydatów, adresy e-mail oraz CV — te dane idą w parze.

Problemy z zapytaniami i filtrowaniem

404 przy wyszukiwaniu konkretnych rekordów

  1. Prefiksowe ID: Ogłoszenia o pracę używają formatu job_abc123, a nie identyfikatorów bazodanowych takich jak 42
  2. Wielkość liter: Prefiksowe ID rozróżniają wielkość liter
  3. Zakres konta: Zasób musi należeć do konta powiązanego z tokenem

Parametry filtrowania nie działają

  1. Dopuszczalne wartości statusów:
    • Ogłoszenia o pracę: draft, published, paused, closed (z uwzględnieniem wielkości liter)
    • Aplikacje: active, rejected (z uwzględnieniem wielkości liter)
  2. Format parametrów: Używaj ?status=published, a nie ?status=Published lub ?filter[status]=published

Często zadawane pytania

Jak działa paginacja?

Wszystkie endpointy listowe zwracają 20 elementów na stronę (wartość stała). Żeby przejść do następnej strony, użyj parametru ?page=2. Obiekt pagination zawiera pola total_pages i total_count.

Czy tokeny wygasają automatycznie?

Nie. Przy tworzeniu tokenu nie ma żadnego ustawienia wygaśnięcia, więc token pozostaje ważny do momentu:

  • Ręcznego unieważnienia w Settings > API
  • Usunięcia użytkownika z konta
  • Usunięcia konta

Czy należy używać jednego tokenu dla wielu integracji?

Nie. Zalecana praktyka to jeden token na integrację z minimalnymi zakresami uprawnień. Ułatwia to:

  • Audyt żądań poszczególnych integracji (poprzez pole last_used_at)
  • Unieważnienie dostępu konkretnej integracji bez wpływu na pozostałe
  • Nadawanie różnych uprawnień różnym systemom

Jaki jest związek między webhookami a API?

Webhooki powiadamiają o zdarzeniach (nowa aplikacja, zmiana etapu). API umożliwia odpytywanie bieżącego stanu. Używaj webhooków do wyzwalania działań w systemie, a następnie API do pobierania pełnych danych.

Czy można pobrać więcej niż 20 elementów na stronę?

Nie. Rozmiar strony jest ustalony na 20 elementów, żeby zapewnić stałą wydajność. Używaj parametru page do iterowania po wszystkich wynikach.

Szybka lista kontrolna

  • Utwórz token API w sekcji Settings > API — każdy token jest powiązany z danym kontem
  • Przypisz tylko te zakresy, których wymaga integracja (zalecana praktyka: jeden token na integrację z minimalnymi zakresami)
  • Nie przyznawaj zakresu candidates:read, jeśli integracja nie musi widzieć danych osobowych kandydatów — ten zakres kontroluje też tablicę metafields i dostęp do CV
  • Dołączaj nagłówek Authorization: Bearer TOKEN do każdego żądania
  • Używaj prefiksowych ID (np. job_abc123) w adresach URL zamiast identyfikatorów bazodanowych
  • Obsługuj odpowiedzi 400 i 422 w przypadku błędów walidacji
  • Obsługuj odpowiedzi 401 — token mógł zostać unieważniony
  • Obsługuj odpowiedzi 403 — token może nie mieć wymaganego zakresu uprawnień
  • Używaj parametru page do paginacji dużych zbiorów wyników (20 elementów na stronę)

Wpisz, aby wyszukać...