Dokumentacja dla programistów

REST API TapTime

Odczyt i aktualizacja rezerwacji stolików i wizyt, odczyt zamówień i kart lojalnościowych, odpytywanie uporządkowanego strumienia zdarzeń i odbieranie podpisanych webhooków — z własnego CRM, systemu POS, hurtowni danych lub platformy automatyzacji. Ta strona to pełna dokumentacja; przewodnik po śledzeniu konwersji wyjaśnia, po co z niej korzystać.

Bazowy URLhttps://api.tapti.me UwierzytelnianieBearer token FormatJSON Po co z tego korzystać

Każde żądanie wymaga klucza API firmy (Integracje → Webhooki i API w panelu) przesyłanego jako Authorization: Bearer tt_live_…. Odpowiedzi i błędy są w formacie JSON.

Potwierdzone rezerwacje zmienione od wskazanej daty
curl "https://api.tapti.me/v1/company/reservations?status=confirmed&updatedSince=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer tt_live_…"

Uwierzytelnianie

Każde żądanie zawiera klucz API firmy jako token typu Bearer. Klucz tworzy się w panelu — Integracje → Webhooki i API → Klucze REST API — gdzie jest wyświetlany jeden raz, a po stronie serwera przechowywany wyłącznie jako skrót SHA-256; utracony klucz się unieważnia i zastępuje nowym, nie da się go odzyskać. Firma może mieć do 10 aktywnych kluczy.

  • Klucze tylko do odczytu mogą wywoływać każdy endpoint GET oraz subskrybować i anulować webhooki — subskrypcja nie wysyła niczego, czego klucz nie mógłby już odczytać.
  • Klucze do odczytu i zapisu mogą dodatkowo wysyłać żądanie POST zmieniające status rezerwacji; klucz tylko do odczytu otrzymuje na tych ścieżkach 403 Forbidden.
  • Klucz należy do jednej firmy — każda lista i każde wyszukiwanie są już do niej zawężone, nie ma parametru companyId.

Limity żądań

50 żądań na minutę na klucz, w oknie przesuwnym, wspólnie dla wszystkich endpointów. Po przekroczeniu zwracany jest kod 429 Too Many Requests; należy odczekać i ponowić żądanie zamiast odpytywać częściej — albo zasubskrybować webhook i przestać odpytywać.

Endpointy

GET /v1/company Tylko odczyt lub odczyt i zapis

Pobranie bieżącej firmy

Firma, do której należy klucz, oraz uprawnienia samego klucza.

GET /v1/company/reservations Tylko odczyt lub odczyt i zapis

Lista rezerwacji stolików

Rezerwacje stolików firmy, od najwcześniejszego terminu rozpoczęcia — a gdy ustawiono updatedSince, od najdawniej zaktualizowanej.

ParametrTypZnaczenie
status string Rozdzielone przecinkami: pending, confirmed, seated, completed, no_show, cancelled. cancelled obejmuje oba powody odwołania.
branchId integer Zawężenie do jednego oddziału.
from ISO 8601 datetime Tylko rezerwacje rozpoczynające się w tym momencie lub później (UTC, jeśli nie podano przesunięcia).
to ISO 8601 datetime Tylko rezerwacje rozpoczynające się przed tym momentem.
updatedSince ISO 8601 datetime Tylko rezerwacje zmienione od tego momentu; przełącza sortowanie na rosnące według updatedAt, na potrzeby synchronizacji.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
page integer Numer strony liczony od 1. Domyślnie 1.
GET /v1/company/appointments Tylko odczyt lub odczyt i zapis

Lista wizyt

Ten sam kształt i te same filtry co w rezerwacjach stolików, dla modułu Wizyty.

ParametrTypZnaczenie
status string Rozdzielone przecinkami: pending, confirmed, completed, no_show, cancelled.
branchId integer Zawężenie do jednego oddziału.
from ISO 8601 datetime Tylko rezerwacje rozpoczynające się w tym momencie lub później.
to ISO 8601 datetime Tylko rezerwacje rozpoczynające się przed tym momentem.
updatedSince ISO 8601 datetime Tylko rezerwacje zmienione od tego momentu; sortowanie rosnące według updatedAt.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
page integer Numer strony liczony od 1. Domyślnie 1.
GET /v1/company/reservations/{id} Tylko odczyt lub odczyt i zapis

Pobranie rezerwacji stolika

Jedna rezerwacja, w tym samym kształcie, w jakim przesyłają ją webhooki, wraz z atrybucją. 404, gdy identyfikator nie należy do firmy klucza.

GET /v1/company/appointments/{id} Tylko odczyt lub odczyt i zapis

Pobranie wizyty

Jedna wizyta, z tym samym kształtem i zasadami co przy pobieraniu rezerwacji stolika.

POST /v1/company/reservations/{id}/status Tylko odczyt i zapis

Zmiana statusu rezerwacji stolika

Potwierdzenie, posadzenie gości, zakończenie, oznaczenie niestawiennictwa, odwołanie lub ponowne otwarcie — wywołuje te same webhooki i konwersje co zmiana na tablicy. Treść JSON: {"status": "..."}.

ParametrTypZnaczenie
status string, wymagany Jedna z wartości: pending, confirmed, seated, completed, no_show, cancelled (akceptowane są też canceled i canceled_by_venue).
POST /v1/company/appointments/{id}/status Tylko odczyt i zapis

Zmiana statusu wizyty

Tak samo jak endpoint rezerwacji stolika, bez stanu seated.

ParametrTypZnaczenie
status string, wymagany Jedna z wartości: pending, confirmed, completed, no_show, cancelled (akceptowane są też canceled i canceled_by_venue).
GET /v1/company/events Tylko odczyt lub odczyt i zapis

Odpytywanie strumienia zdarzeń

Wszystkie zdarzenia dotyczące rezerwacji, zamówień i lojalności, od najstarszego — ten sam strumień, z którego powstają webhooki. Ostatni widziany kursor przekazany jako after zwraca tylko nowe zdarzenia, a type — tylko wybrane rodzaje.

ParametrTypZnaczenie
after integer, kursor Kursor ostatniego przetworzonego zdarzenia. Bez tego parametru odczyt zaczyna się od początku.
type string Typy lub rodziny zdarzeń rozdzielone przecinkami: booking.confirmed,order.placed albo order, loyalty.*. Bez tego parametru zwracane są wszystkie zdarzenia.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
GET /v1/company/orders Tylko odczyt lub odczyt i zapis

Lista zamówień

Zamówienia gości przy stoliku, na wynos i z dostawą oraz każda sprzedaż nabita na kasie, od najstarszego — a gdy ustawiono paidSince, w kolejności opłacenia. Zamówienie wciąż oczekujące na przedpłatę jest pomijane.

ParametrTypZnaczenie
status string Rozdzielone przecinkami: open, paid.
source string customer (złożone przez gościa) lub staff (nabite przez personel).
fulfilment string Rozdzielone przecinkami: dine_in, takeaway, delivery.
branchId integer Zawężenie do jednego oddziału.
from ISO 8601 datetime Tylko zamówienia utworzone w tym momencie lub później.
to ISO 8601 datetime Tylko zamówienia utworzone przed tym momentem.
paidSince ISO 8601 datetime Tylko zamówienia opłacone od tego momentu; sortowanie rosnące według paidAt, na potrzeby synchronizacji sprzedaży.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
page integer Numer strony liczony od 1. Domyślnie 1.
GET /v1/company/orders/{id} Tylko odczyt lub odczyt i zapis

Pobranie zamówienia

Jedno zamówienie z pozycjami, sumami i atrybucją, w kształcie, w jakim przesyłają je webhooki zamówień.

GET /v1/company/loyalty/programs Tylko odczyt lub odczyt i zapis

Lista programów lojalnościowych

Wszystkie programy z kartą pieczątek: nazwa, status, wymagana liczba pieczątek, nagroda i miejsce, w którym obowiązuje.

GET /v1/company/loyalty/cards Tylko odczyt lub odczyt i zapis

Lista kart lojalnościowych

Karty uczestników w kształcie obiektu lojalnościowego. Uczestnik, który zapełnił kartę, ma ją w stanie completed, a obok nową, aktywną; customer.id to uczestnik.

ParametrTypZnaczenie
programId integer Zawężenie do jednego programu.
customerId integer Zawężenie do jednego uczestnika.
status string Rozdzielone przecinkami: active, completed.
updatedSince ISO 8601 datetime Tylko karty ostemplowane lub zakończone od tego momentu; sortowanie rosnące według updatedAt.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
page integer Numer strony liczony od 1. Domyślnie 1.
GET /v1/company/loyalty/rewards Tylko odczyt lub odczyt i zapis

Lista nagród lojalnościowych

Nagrody zdobyte po zapełnieniu karty, z kodem, terminem ważności i informacją, czy zostały wydane.

ParametrTypZnaczenie
programId integer Zawężenie do jednego programu.
customerId integer Zawężenie do jednego uczestnika.
status string Rozdzielone przecinkami: issued, redeemed, expired.
from ISO 8601 datetime Tylko nagrody przyznane w tym momencie lub później.
to ISO 8601 datetime Tylko nagrody przyznane przed tym momentem.
limit integer Rozmiar strony, 1–100. Domyślnie 50.
page integer Numer strony liczony od 1. Domyślnie 1.
GET /v1/company/webhooks Tylko odczyt lub odczyt i zapis

Lista subskrypcji webhooków

Subskrypcje utworzone przez ten klucz. Webhooki dodane w panelu nie są tu wymieniane.

POST /v1/company/webhooks Tylko odczyt lub odczyt i zapis

Subskrypcja webhooka

Rozpoczyna wysyłanie zdarzeń na adres URL — to wywołuje aplikacja platformy automatyzacji, gdy użytkownik włącza wyzwalacz. Zwraca subskrypcję i jej klucz podpisu, jednorazowo. Treść JSON: {"url": "…", "events": ["order.placed"]}; akceptowany jest też format Zapier {"target_url": "…", "event": "…"}.

ParametrTypZnaczenie
url string, wymagany Adres https, na który są wysyłane zdarzenia (akceptowany jest też target_url).
events tablica stringów, wymagana Typy zdarzeń, rodziny takie jak order.* lub loyalty albo * dla wszystkich (akceptowane jest też event, dla jednego).
description string Nazwa wyświetlana w panelu. Domyślnie nazwa platformy i nazwa klucza.
DELETE /v1/company/webhooks/{id} Tylko odczyt lub odczyt i zapis

Anulowanie subskrypcji webhooka

Zatrzymuje wysyłanie do subskrypcji utworzonej przez ten klucz. Zwraca 204. Unieważnienie klucza usuwa również wszystkie jego subskrypcje.

Obiekt rezerwacji

Rezerwacja stolika i wizyta mają jeden wspólny kształt: kind, id, status, source, guestInitiated, startsAt/endsAt/timezone (strefa czasowa oddziału), currency, company, branch, guest, attribution, conversionId, createdAt/updatedAt — a do tego partySize i table dla rezerwacji stolika oraz service i specialist dla wizyty. To dokładnie to, co dostarcza webhook, więc odbiorca obsługujący jedno obsługuje oba.

GET /v1/company/reservations/4821 → data
{
  "data": {
    "kind": "reservation",
    "id": 4821,
    "status": "confirmed",
    "source": "online",
    "guestInitiated": true,
    "startsAt": "2026-09-12T20:00:00+03:00",
    "endsAt": "2026-09-12T21:30:00+03:00",
    "timezone": "Asia/Baku",
    "currency": "AZN",
    "company": { "id": 12, "name": "Cafe Aroma", "slug": "cafe-aroma", "country": "AZ" },
    "branch": { "id": 3, "name": "Nizami st." },
    "partySize": 4,
    "table": { "id": 9, "label": "T3" },
    "guest": { "name": "Maria K.", "phone": "…", "email": "…" },
    "locale": "en",
    "note": null,
    "conversionId": "tt3f9c…",
    "createdAt": "2026-09-10T08:12:04+00:00",
    "updatedAt": "2026-09-12T20:00:03+00:00",
    "attribution": { "channel": "widget", "utmSource": "instagram", "gclid": null, "fbclid": "IwAR2…" }
  }
}

Obiekt zamówienia

Zamówienie ma jeden kształt, niezależnie od miejsca, w którym się pojawia — REST API, webhooki zamówień, strumień zdarzeń: kind ("order"), id, number (numer wywoływany przez personel), status (open lub paid), source (customer lub staff), guestInitiated, fulfilment, table, label, deliveryAddress, note, currency, timezone, company, branch, customer (uczestnik programu lojalnościowego, jeśli personel go zidentyfikował), items (name, variant, quantity, unitPriceCents, subtotalCents), itemCount, subtotalCents, discountCents, deliveryFeeCents, tipCents, totalCents, valueCents (wartość zamówienia bez napiwku — liczba raportowana w konwersjach), paymentMethod, servedBy, conversionId, createdAt, paidAt i attribution. Kwoty są zawsze w jednostkach podrzędnych waluty (np. groszach).

GET /v1/company/orders/9170 → data
{
  "data": {
    "kind": "order",
    "id": 9170,
    "number": 42,
    "status": "paid",
    "source": "customer",
    "guestInitiated": true,
    "fulfilment": "takeaway",
    "table": null,
    "label": "Ana",
    "currency": "EUR",
    "branch": { "id": 3, "name": "Vitosha Blvd" },
    "customer": { "id": 311, "name": "Ana", "phone": "…" },
    "items": [
      { "menuItemId": 88, "name": "Flat white", "variant": "Large",
        "quantity": 2, "unitPriceCents": 450, "subtotalCents": 900 }
    ],
    "itemCount": 2,
    "subtotalCents": 900,
    "discountCents": 0,
    "deliveryFeeCents": 0,
    "tipCents": 100,
    "totalCents": 1000,
    "valueCents": 900,
    "paymentMethod": "online",
    "conversionId": "tt81ad…",
    "createdAt": "2026-09-12T12:04:10+03:00",
    "paidAt": "2026-09-12T12:05:02+03:00",
    "attribution": { "channel": "web", "utmSource": "google", "gclid": "Cj0K…" }
  }
}

Obiekt lojalnościowy

Każde zdarzenie lojalnościowe, karta i nagroda mają jeden wspólny kształt: kind ("loyalty"), id (karta), timezone, company, branch (miejsce zdarzenia, jeśli jest), program (id, name, stampsRequired, rewardTitle), customer (id, name, phone, locale), card (id, status, stampsCount, stampsRequired, stampsToReward, createdAt), stamp (dla pieczątki: source, issuedBy, createdAt) i reward (dla nagrody: code, title, status, expiresAt, redeemedAt, redeemedBy), a także conversionId — identyfikator, pod którym raportowane jest dołączenie do programu lojalnościowego.

GET /v1/company/loyalty/cards → data[0]
{
  "kind": "loyalty",
  "id": 5120,
  "program": { "id": 4, "name": "Coffee card", "stampsRequired": 8, "rewardTitle": "Free coffee" },
  "customer": { "id": 311, "name": "Ana", "phone": "…", "locale": "bg" },
  "card": { "id": 5120, "status": "active", "stampsCount": 5,
            "stampsRequired": 8, "stampsToReward": 3 },
  "branch": { "id": 3, "name": "Vitosha Blvd" },
  "stamp": { "source": "qr_scan", "issuedBy": "Ivan", "createdAt": "…" },
  "reward": null,
  "conversionId": "tt5c02…"
}

Strumień zdarzeń

Każdy wiersz to { id, cursor, type, createdAt, previousStatus, data }. data zawiera obiekt pod kluczem wskazanym przez prefiks zdarzenia: data.booking, data.order lub data.loyalty. Należy zapisywać najwyższy przetworzony kursor i przekazywać go z powrotem jako after — nigdy nie pomija ani nie powtarza wiersza, więc można bezpiecznie wznowić pracę po awarii. Nieobsługiwane typy należy ignorować: mogą pojawiać się nowe.

Typ zdarzeniaZnaczenie
booking.requestedGość poprosił o rezerwację, która czeka na potwierdzenie przez lokal.
booking.confirmedRezerwacja została potwierdzona — od razu przy utworzeniu lub później przez personel.
booking.cancelledOdwołana przez gościa lub lokal; wskazuje to pole status.
booking.no_showGość się nie pojawił.
booking.completedWizyta dobiegła końca.
order.placedZamówienie gościa dotarło do lokalu — ze strony, z kodu QR przy stoliku, na wynos lub z dostawą; po płatności, jeśli lokal pobiera ją z góry.
order.paidDowolne zamówienie zostało rozliczone, w tym sprzedaż nabita na kasie.
loyalty.member_joinedKlient otrzymał pierwszą pieczątkę w programie.
loyalty.stamp_addedDo karty dodano pieczątkę.
loyalty.reward_issuedKarta została zapełniona i przyznano nagrodę.
loyalty.reward_redeemedNagroda została wydana.
Synchronizacja ze strumieniem zdarzeń
curl "https://api.tapti.me/v1/company/events?after=998&limit=100" \
  -H "Authorization: Bearer tt_live_…"

Webhooki

Wystarczy utworzyć endpoint w sekcji Integracje → Webhooki i API — lub podłączyć Zapier, Make, n8n albo Pipedream w sekcji Integracje → Automatyzacja — a TapTime wyśle żądanie POST z podpisanym zdarzeniem JSON w chwili, gdy zmieni się rezerwacja, zamówienie lub karta lojalnościowa. Zdarzenia wybiera się dla każdego endpointu osobno. Firma może mieć łącznie do 50 webhooków, postbacków, czatów i połączeń z platformami automatyzacji.

NagłówekZnaczenie
TapTime-EventTyp zdarzenia, np. booking.confirmed.
TapTime-Event-IdStały identyfikator zdarzenia — służy do usuwania duplikatów przy ponownym doręczeniu.
TapTime-DeliveryIdentyfikator tej konkretnej próby doręczenia.
TapTime-Signaturet=<czas unix>,v1=<szesnastkowy HMAC-SHA256 z "t.rawBody">, podpisany własnym kluczem tajnym endpointu.
  • Każda odpowiedź 2xx oznacza doręczenie; odpowiedź inna niż 2xx lub przekroczenie czasu skutkuje ponowieniem z rosnącymi odstępami (1m, 5m, 15m, 1h, 3h, 6h, 12h), maksymalnie 8 prób — odpowiedź 410 kończy ponawianie.
  • Przekierowania nie są obsługiwane.
  • W środowisku produkcyjnym adres URL musi używać HTTPS i nie może wskazywać na adres prywatny ani pętli zwrotnej.
  • Doręczenie odbywa się co najmniej raz: zawsze należy weryfikować podpis i usuwać duplikaty według TapTime-Event-Id.
POST · application/json · booking.confirmed
{
  "id": "evt_9f3c2a7e1b",
  "type": "booking.confirmed",
  "createdAt": "2026-09-12T19:02:11+03:00",
  "test": false,
  "data": { "booking": { "kind": "reservation", "id": 4821, "status": "confirmed", "…": "…" } }
}
Weryfikacja podpisu (Node.js)
const [t, v1] = req.headers["taptime-signature"]
  .split(",").map(part => part.split("=")[1]);
const expected = crypto
  .createHmac("sha256", process.env.TAPTIME_WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`)
  .digest("hex");
const valid = crypto.timingSafeEqual(
  Buffer.from(expected), Buffer.from(v1));

Subskrypcje webhooków

Platformy automatyzacji włączają i wyłączają wyzwalacze przez API, zamiast prosić użytkownika o wklejenie adresu URL („REST hooks”): wysyłają żądanie POST z własnym adresem URL platformy i żądanymi zdarzeniami, zachowują zwrócony identyfikator i wysyłają DELETE po wyłączeniu wyzwalacza. Subskrypcja to zwykły podpisany webhook — widoczny w panelu i oznaczony kluczem, który go utworzył.

  • Klucz widzi i usuwa wyłącznie utworzone przez siebie subskrypcje; unieważnienie klucza usuwa je wszystkie.
  • Adresy w domenach hooks.zapier.com, make.com i pipedream.net są rozpoznawane i wyświetlane z nazwą platformy; każdy inny adres https to zwykły webhook.
  • Klucz podpisu jest zwracany jeden raz, w odpowiedzi na żądanie POST; właściciel może go ponownie wyświetlić w panelu.
Subskrypcja adresu URL dla nowych zamówień
curl -X POST "https://api.tapti.me/v1/company/webhooks" \
  -H "Authorization: Bearer tt_live_…" -H "Content-Type: application/json" \
  -d '{"url": "https://hooks.zapier.com/hooks/catch/123/abc/", "events": ["order.placed"]}'

Postbacki

Żądanie GET lub POST na własny adres URL trackera z wypełnionymi makrami — dla platform, które obsługują postbacki w parametrach zapytania zamiast webhooków JSON. W przypadku zamówienia {value} to wartość zamówienia bez napiwku, a {order_id} — jego identyfikator.

URL postbacku z makrami · GET lub POST
https://tracker.example/postback
  ?cid={click_id}&event={event}&status={status}
  &payout={value}&cur={currency}

Dostępne makra

  • {event}
  • {event_id}
  • {status}
  • {booking_id}
  • {booking_type}
  • {order_id}
  • {customer_id}
  • {conversion_id}
  • {value}
  • {currency}
  • {party_size}
  • {branch_id}
  • {timestamp}
  • {utm_source}
  • {utm_medium}
  • {utm_campaign}
  • {utm_term}
  • {utm_content}
  • {gclid}
  • {fbclid}
  • {msclkid}
  • {ttclid}
  • {click_id}

Błędy

Każdy błąd jest zwracany w formacie JSON: { "error": "<kod>", "message": "<opis czytelny dla człowieka>" }.

StatusbłądZnaczenie
401 unauthorized Brak nagłówka Authorization albo klucz jest nieprawidłowy lub unieważniony.
403 forbidden Klucz tylko do odczytu wywołał endpoint zapisu (zmianę statusu).
404 not_found Żadna rezerwacja o tym identyfikatorze nie należy do firmy klucza.
409 conflict Zmiana statusu spowodowałaby podwójną rezerwację stolika lub terminu; niczego nie zmieniono.
422 invalid_status Wartość status w treści żądania nie należy do wartości akceptowanych dla danego typu rezerwacji.
422 invalid_type Parametr type strumienia zdarzeń nie wskazuje żadnego typu ani rodziny zdarzeń.
422 invalid_url Adres URL subskrypcji nie jest publicznym adresem https.
429 rate_limited Ponad 50 żądań na minutę dla tego klucza. Należy zwolnić i ponowić żądanie.
Potrzebują Państwo klucza?

Dostęp do API, webhooki oraz integracje z platformami automatyzacji i czatami są w cenie każdego modułu — bez dodatkowych opłat i bez osobnego planu dla programistów.

Rozpocznij bezpłatny okres próbny