API
OctaForms udostępnia HTTP API do zarządzania formularzami i zgłoszeniami z Twojego serwera. Adresy
w przykładach zaczynają się od https://app.octaforms.pl, podstaw adres swojej instancji.
Są dwie grupy endpointów:
- Publiczne (
/api/v1/public/...) bez uwierzytelniania, używa ich widget na stronie. - Zarządzające (
/api/v1/admin/...) wymagają klucza API, to jest właściwe API integracyjne (formularze, pola, pobieranie zgłoszeń).
Uwierzytelnianie
Dział zatytułowany „Uwierzytelnianie”Endpointy /api/v1/admin/... wymagają klucza API. Prześlij go w nagłówku:
X-Api-Key: <twój-klucz>Alternatywnie zadziała Authorization: Bearer <twój-klucz>.
Klucz otrzymujesz od operatora instancji (na razie nie ma samoobsługowego generowania kluczy).
Przy błędnym lub brakującym kluczu API zwraca 401 w formacie application/problem+json.
Format odpowiedzi i błędów
Dział zatytułowany „Format odpowiedzi i błędów”Odpowiedzi są w JSON. Błędy zwracane są jako application/problem+json (RFC 9457). Błąd walidacji to
status 422 z listą violations:
{ "type": "about:blank", "title": "Unprocessable Entity", "status": 422, "detail": "Validation failed.", "violations": [ { "field": "email", "message": "Email is required", "code": "required" } ]}Najczęstsze statusy:
| Status | Znaczenie |
|---|---|
401 |
brak lub błędny klucz API (endpointy admin) |
404 |
formularz lub zgłoszenie nie istnieje |
409 |
konflikt: np. nazwa formularza zajęta, formularz nieaktywny lub bez opublikowanej wersji |
422 |
błąd walidacji (patrz violations) |
429 |
przekroczony limit zapytań (endpoint publiczny) |
Formularze
Dział zatytułowany „Formularze”Tworzenie formularza
Dział zatytułowany „Tworzenie formularza”POST /api/v1/admin/forms
Pola górnego poziomu: formName (wymagane), projectId (wymagane, identyfikator projektu z panelu),
opcjonalnie submitLabel, thankYouPageUrl, thankYou ({title, text}) oraz inputs (pola formularza).
thankYouPageUrl przyjmuje też placeholdery wypełniane wartościami ze zgłoszenia, np.
https://twoja-strona.pl/dziekujemy?f={form_id}. Zasady i ostrzeżenie o danych osobowych opisuje
Osadzanie.
{ "formName": "Formularz kontaktowy", "projectId": "0193aaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "submitLabel": "Wyślij", "thankYouPageUrl": "https://twoja-strona.pl/dziekujemy", "thankYou": { "title": "Dziękujemy!", "text": "Odezwiemy się wkrótce." }, "inputs": { "name": { "type": "text", "options": {}, "rules": [ { "rule": "required", "errorMessage": "Podaj imię" }, { "rule": "max:120", "errorMessage": "Imię jest za długie" } ] }, "email": { "type": "email", "options": {}, "rules": [ { "rule": "required", "errorMessage": "Podaj adres e-mail" } ] }, "topic": { "type": "select", "options": { "choices": ["Sprzedaż", "Wsparcie", "Inne"] }, "rules": [ { "rule": "required", "errorMessage": "Wybierz temat" } ] }, "consent": { "type": "checkbox", "options": {}, "rules": [ { "rule": "required", "errorMessage": "Zgoda jest wymagana" } ] } }}Sukces: 201 Created, ciało to identyfikator nowego formularza (JSON string). Zduplikowana nazwa
formularza zwraca 409.
Pola (inputs)
Dział zatytułowany „Pola (inputs)”inputs to mapa, w której klucz jest nazwą pola (tej nazwy użyjesz potem w danych zgłoszenia
i w payloadzie webhooka). Każdy wpis to obiekt z trzema kluczami: type, options, rules.
Wszystkie trzy są wymagane (options może być {}, rules może być []).
Typy pól (type):
| Typ | Opis |
|---|---|
text |
jednoliniowy tekst |
textarea |
wieloliniowy tekst |
email |
adres e-mail (reguła email dokładana automatycznie) |
phone |
telefon (reguła phone dokładana automatycznie) |
number |
liczba |
select |
lista wyboru |
radio |
przyciski jednokrotnego wyboru |
checkbox |
pole zaznaczenia (np. zgoda) |
date |
data |
hidden |
pole ukryte |
Dla select i radio warianty podajesz w options (np. {"choices": ["A", "B"]}). options jest
przekazywane do widgetu bez zmian, backend go nie waliduje.
Reguły (rules): lista obiektów { "rule": ..., "errorMessage": ... }. errorMessage musi mieć
co najmniej 3 znaki. Obsługiwane reguły:
| Reguła | Znaczenie |
|---|---|
required |
wartość wymagana |
email |
poprawny e-mail |
phone |
poprawny telefon |
numeric |
wartość liczbowa |
min:<n> |
długość tekstu ≥ n (lub wartość ≥ n dla pól liczbowych) |
max:<n> |
długość tekstu ≤ n (lub wartość ≤ n dla pól liczbowych) |
nip |
polski NIP |
postCodePL |
polski kod pocztowy |
Publikacja i stan formularza
Dział zatytułowany „Publikacja i stan formularza”Nowy lub zmieniony formularz trzeba opublikować, żeby widget mógł go renderować:
POST /api/v1/admin/forms/{formId}/publishpublikuje wersję, zwraca201{ "version": <n>, "created": true }. Publikacja jest idempotentna: jeśli od ostatniej publikacji nic się w definicji nie zmieniło, nowa wersja nie powstaje, a odpowiedź to200{ "version": <n>, "created": false }z numerem wersji, która nadal działa.POST /api/v1/admin/forms/{formId}/enablewłącza formularzPOST /api/v1/admin/forms/{formId}/disablewyłącza formularzPUT /api/v1/admin/forms/{formId}edytuje formularz (to samo ciało co przy tworzeniu)DELETE /api/v1/admin/forms/{formId}usuwa formularz (204)
Odczyt formularzy
Dział zatytułowany „Odczyt formularzy”GET /api/v1/admin/formslista z paginacją. Parametry zapytania:limit(domyślnie 25),offset(domyślnie 0),formName,projectId,status(bool, domyślnietrue).GET /api/v1/admin/forms/{formId}pojedynczy formularz.GET /api/v1/public/forms/{formId}publiczna definicja opublikowanego formularza (bez klucza), tej używa widget. Zwraca m.in. nazwy pól, przydatne gdy budujesz własny frontend.
Zgłoszenia (leady)
Dział zatytułowany „Zgłoszenia (leady)”GET /api/v1/admin/leadslista z paginacją. Parametry:limit,offset,formName,projectId.GET /api/v1/admin/leads/{leadId}pojedyncze zgłoszenie wraz z historią dostaw (deliveries).DELETE /api/v1/admin/leads/{leadId}usuwa zgłoszenie (204).
Tworzenie zgłoszenia z serwera
Dział zatytułowany „Tworzenie zgłoszenia z serwera”POST /api/v1/admin/forms/{formId}/leads (z kluczem API) tworzy zgłoszenie bez zabezpieczeń
antybotowych, do integracji server-to-server:
{ "fields": { "name": "Jan Kowalski", "email": "jan@example.com", "consent": true }, "meta": { "source": "import-crm" }}Wartości fields są walidowane regułami formularza, tak samo jak przy wysyłce publicznej.
Wysyłka publiczna (bez klucza)
Dział zatytułowany „Wysyłka publiczna (bez klucza)”Widget na stronie wysyła zgłoszenia na POST /api/v1/public/forms/{formId}/leads. Zwykle nie robisz
tego ręcznie, od tego jest osadzanie formularza. Jeśli jednak
wysyłasz z własnego frontendu, pamiętaj o zabezpieczeniu antybotowym:
- Pobierz token:
GET /api/v1/public/forms/{formId}/tokenzwraca{ "token": "..." }. - Wyślij zgłoszenie, dołączając
antibot:
{ "fields": { "email": "jan@example.com", "name": "Jan" }, "meta": {}, "antibot": { "hp": "", "t": "<token-z-kroku-1>" }}Zasady: pole honeypot hp musi być puste, a od pobrania tokenu do wysyłki muszą minąć co najmniej
3 sekundy (token ważny 24 godziny). Sukces to 201 z { "redirectUrl": ... }. Przy wykryciu bota
odpowiedź jest udawanym sukcesem (201 z redirectUrl: null), a przy odrzuceniu tokenu 403.
Interaktywna dokumentacja
Dział zatytułowany „Interaktywna dokumentacja”Na działającej instancji dostępny jest interaktywny podgląd API (Swagger UI):
GET /api/public/docendpointy publiczneGET /api/admin/docendpointy zarządzające