Przejdź do głównej zawartości

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ń).

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.

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)

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.

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

Nowy lub zmieniony formularz trzeba opublikować, żeby widget mógł go renderować:

  • POST /api/v1/admin/forms/{formId}/publish publikuje wersję, zwraca 201 { "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ź to 200 { "version": <n>, "created": false } z numerem wersji, która nadal działa.
  • POST /api/v1/admin/forms/{formId}/enable włącza formularz
  • POST /api/v1/admin/forms/{formId}/disable wyłącza formularz
  • PUT /api/v1/admin/forms/{formId} edytuje formularz (to samo ciało co przy tworzeniu)
  • DELETE /api/v1/admin/forms/{formId} usuwa formularz (204)
  • GET /api/v1/admin/forms lista z paginacją. Parametry zapytania: limit (domyślnie 25), offset (domyślnie 0), formName, projectId, status (bool, domyślnie true).
  • 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.
  • GET /api/v1/admin/leads lista 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).

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.

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:

  1. Pobierz token: GET /api/v1/public/forms/{formId}/token zwraca { "token": "..." }.
  2. 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.

Na działającej instancji dostępny jest interaktywny podgląd API (Swagger UI):

  • GET /api/public/doc endpointy publiczne
  • GET /api/admin/doc endpointy zarządzające