Uwierzytelnianie
Wszystkie żądania API wykorzystują klucz API jako token typu bearer. Utwórz go w aplikacji w sekcji Developer → API keys. Klucze mogą być tylko do odczytu lub do odczytu i zapisu.
curl https://savrsoft.com/api/v1/events \ -H "Authorization: Bearer savr_live_your_key_here"
Adres bazowy: https://savrsoft.com/api/v1 · Wszystkie odpowiedzi są w formacie JSON. Błędy zwracają { "error": "…" } ze statusem 4xx/5xx.
Kody statusu
| Kod | Kiedy go otrzymujesz |
|---|---|
200 | Odczyt zakończony powodzeniem. |
201 | Utworzono pomyślnie. Treść odpowiedzi to { "id": 42 } — pobierz rekord, jeśli potrzebujesz reszty danych. |
400 | Brakuje wymaganego pola, np. { "error": "name is required" }, lub nie udało się odczytać kursora paginacji. |
401 | Brak klucza API, klucz nieprawidłowy lub klucz, który został unieważniony. |
403 | Użyto klucza tylko do odczytu przy operacji zapisu. Utwórz klucz do odczytu i zapisu w Developer → API keys. |
404 | Rekord nie istnieje lub należy do innej organizacji — te dwa przypadki są celowo nierozróżnialne. Ten sam błąd zwracany jest też dla nierozpoznanej ścieżki lub metody. |
Zakres tego API
API umożliwia tylko odczyt i tworzenie. Nie ma tu DELETE, PUT ani PATCH
punktów końcowych — żądanie z ich użyciem zwraca 404 Unknown endpoint, tak samo jak każda nierozpoznana ścieżka. Usuwanie i
edycja odbywają się w aplikacji, dzięki czemu integracja nie może zniszczyć danych cateringu. Jeśli potrzebujesz dostępu do zapisu wykraczającego poza tworzenie,
napisz nam, co budujesz.
Paginacja
Każdy punkt końcowy listy jest stronicowany. Przekaż limit (domyślnie 100, maksymalnie 500) i
podążaj za next_cursor aż has_more będzie false:
{
"data": [ ... ],
"has_more": true,
"next_cursor": "eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0"
}
Przekaż kursor bezpośrednio, aby pobrać następną stronę. Traktuj go jako nieprzejrzysty ciąg — kodowanie może się zmienić:
curl "https://savrsoft.com/api/v1/clients?limit=100&cursor=eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0" \ -H "Authorization: Bearer savr_live_your_key_here"
Stronicowanie jest zakotwiczone względem ostatniego otrzymanego wiersza, a nie przesunięcia, więc wiersze utworzone lub usunięte w trakcie stronicowania nie spowodują pominięcia ani powtórzenia rekordu. Kursor pozostaje ważny bezterminowo.
| Parametr | Zachowanie |
|---|---|
limit | 1–500. Brak wartości, zero, wartość ujemna lub nienumeryczna powoduje przyjęcie wartości domyślnej 100; wszystko powyżej 500 jest ograniczane do 500. |
cursor | next_cursor z poprzedniej strony. Pomiń dla pierwszej strony. Kursor, którego nie można odczytać — uszkodzony lub pochodzący z innego endpointu — zwraca 400 Invalid cursor zamiast po cichu zaczynać od początku. |
Kolejność: /events i /invoices od najnowszych; /recipes i
/clients alfabetycznie według nazwy, a remisy są rozstrzygane według id, dzięki czemu stronicowanie pozostaje stabilne, gdy nazwy się powtarzają.
Endpointy
/v1/meTwoja organizacja (id, nazwa, waluta).
/v1/eventsLista wydarzeń, od najnowszych. Stronicowane — patrz Stronicowanie powyżej.
/v1/events/{id}Jedno wydarzenie z jego daniami.
/v1/events · wymaga uprawnień odczytu/zapisuUtwórz wydarzenie. Treść:
{ "name": "Acme holiday party", "event_date": "2026-12-18",
"guests": 120, "price_per_head": 55, "event_type": "corporate" }
/v1/recipes · GET/v1/recipes/{id}Lista przepisów (z alergenami i oznaczeniami diet) lub jeden przepis ze składnikami. Lista jest stronicowana i posortowana alfabetycznie.
/v1/clients · POST/v1/clientsLista klientów (stronicowana, alfabetycznie) lub utworzenie nowego. Treść żądania: { "name": "...", "email": "...", "phone": "...", "company": "..." }
/v1/invoices · GET/v1/invoices/{id}Lista faktur z wyliczonymi sumami, od najnowszych, lub jedna faktura z pozycjami. Lista jest stronicowana.
Webhooki
Zarejestruj endpoint w sekcji Developer → Webhooks. Wysyłamy POST z danymi JSON, gdy wystąpi zdarzenie:
{
"id": "evt_abc123",
"type": "event.inquiry",
"created_at": "2026-07-17T18:20:00.000Z",
"data": { "id": 42, "name": "Corporate lunch — Dana Ruiz", ... }
}
Typy zdarzeń
| Typ | Uruchamiane, gdy |
|---|---|
event.created | Zdarzenie zostaje utworzone |
event.inquiry | Wpływa nowe zapytanie cateringowe online |
invoice.sent | Faktura zostaje oznaczona jako wysłana |
invoice.paid | Faktura zostaje oznaczona jako opłacona |
proposal.approved | Klient zatwierdza ofertę |
client.created | Klient zostaje utworzony |
Weryfikacja podpisów
Każda dostawa zawiera nagłówek x-savrsoft-signature : HMAC-SHA256 surowej treści żądania, podpisany kluczem webhooka. Oblicz to samo i porównaj:
// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', SIGNING_SECRET)
.update(rawBody).digest('hex');
if (sig !== req.headers['x-savrsoft-signature']) reject();
