Fiecare solicitare necesită o cheie API a companiei (Integrări → Webhooks și API în panoul de control), trimisă sub forma „Authorization: Bearer tt_live_….”. Răspunsurile și erorile sunt în format JSON.
curl "https://api.tapti.me/v1/company/reservations?status=confirmed&updatedSince=2026-09-01T00:00:00Z" \
-H "Authorization: Bearer tt_live_…"
Autentificare
Fiecare solicitare conține o cheie API a companiei ca token de tip „bearer”. Creați una din panoul de control — Integrări → Webhooks și API → Chei API REST — unde aceasta este afișată o singură dată și stocată pe server doar sub forma unui hash SHA-256; o cheie pierdută este revocată și înlocuită, nu recuperată. O companie poate deține până la 10 chei active.
- Cheile doar pentru citire pot apela orice endpoint GET și pot abona sau dezabona webhook-uri — o abonare nu trimite nimic din ce cheia nu ar putea deja citi.
- Cheile de citire-scriere pot, în plus, să schimbe prin POST starea unei rezervări; o cheie doar pentru citire primește 403 Forbidden pe aceste rute.
- O cheie aparține unei singure companii — fiecare listă și căutare este deja limitată la ea; nu există parametrul companyId.
Limite de rată
50 de cereri pe minut pentru fiecare cheie, într-o fereastră glisantă, comune tuturor endpointurilor. La depășire răspunsul este 429 Too Many Requests; așteptați și reîncercați în loc să interogați mai des — sau abonați un webhook și renunțați la interogări.
Puncte terminale
/v1/company
Doar citire sau citire-scriere
Află care este compania actuală
Compania căreia îi aparține cheia și ce poate face cheia în sine.
/v1/company/reservations
Doar citire sau citire-scriere
Lista rezervărilor
Rezervările de mese pentru companie, ordonate după ora de începere cea mai veche — sau, atunci când este setată opțiunea updatedSince, ordonate după data de actualizare cea mai veche.
| Parametru | Type | Înțeles |
|---|---|---|
status |
string | Separate prin virgulă: în așteptare, confirmat, prezent, finalizat, neprezentat, anulat. Valoarea „anulat” corespunde ambelor motive de anulare. |
branchId |
integer | Limitați-vă la o singură ramură. |
from |
ISO 8601 datetime | Doar rezervările care încep la această oră sau după aceasta (UTC, dacă nu se specifică niciun decalaj). |
to |
ISO 8601 datetime | Doar rezervările care încep înainte de această oră. |
updatedSince |
ISO 8601 datetime | Doar rezervările modificate de atunci; comută ordonarea la updatedAt în ordine crescătoare, pentru sincronizare. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
page |
integer | Numerotarea paginilor începând de la 1. Valoarea implicită este 1. |
/v1/company/appointments
Doar citire sau citire-scriere
Afișează programările
Același format și aceleași filtre ca în cazul rezervărilor, pentru modulul „Programări”.
| Parametru | Type | Înțeles |
|---|---|---|
status |
string | Separate prin virgulă: în așteptare, confirmate, finalizate, neprezentare, anulate. |
branchId |
integer | Limitați-vă la o singură ramură. |
from |
ISO 8601 datetime | Doar rezervările care încep la această dată sau după aceasta. |
to |
ISO 8601 datetime | Doar rezervările care încep înainte de această dată. |
updatedSince |
ISO 8601 datetime | Doar rezervările modificate de atunci; ordonate în ordine crescătoare după updatedAt. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
page |
integer | Numerotare pagini începând de la 1. Valoarea implicită este 1. |
/v1/company/reservations/{id}
Doar citire sau citire-scriere
Fă o rezervare
O singură rezervă, în același format în care o transmit webhook-urile, cu mențiunea sursei. Cod de eroare 404 atunci când ID-ul nu aparține companiei asociate cheii.
/v1/company/appointments/{id}
Doar citire sau citire-scriere
Programează-te
O programare, cu același format și aceleași reguli ca și în cazul căutării unei rezervări.
/v1/company/reservations/{id}/status
Numai citire-scriere
Modificarea stării unei rezervări
Confirmare, alocare loc, finalizare, marcare ca „absent”, anulare sau redeschidere — declanșează aceleași webhook-uri și conversii ca și modificarea efectuată direct pe tablă. Corpul JSON: {"status": "..."}.
| Parametru | Type | Înțeles |
|---|---|---|
status |
string, required | Una dintre următoarele: în așteptare, confirmat, prezent, finalizat, neprezentat, anulat (se acceptă și „canceled” și „canceled_by_venue”). |
/v1/company/appointments/{id}/status
Numai citire-scriere
Modificarea stării unei programări
La fel ca punctul final de rezervare, fără starea „așezat”.
| Parametru | Type | Înțeles |
|---|---|---|
status |
string, required | Una dintre următoarele: în așteptare, confirmat, finalizat, neprezentare, anulat (se acceptă și variantele „canceled” și „canceled_by_venue”). |
/v1/company/events
Doar citire sau citire-scriere
Interoghează fluxul de evenimente
Fiecare eveniment de rezervare, comandă și fidelizare, de la cel mai vechi — același flux din care sunt trimise webhook-urile. Transmiteți ultimul cursor văzut ca after ca să primiți doar noutățile și type ca să primiți doar anumite tipuri.
| Parametru | Type | Înțeles |
|---|---|---|
after |
integer cursor | Cursorul ultimului eveniment procesat. Omiteți-l ca să începeți de la început. |
type |
string | Tipuri sau familii de evenimente, separate prin virgulă: booking.confirmed,order.placed sau order, loyalty.*. Omiteți-l pentru toate evenimentele. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
/v1/company/orders
Doar citire sau citire-scriere
Lista comenzilor
Comenzile oaspeților la masă, la pachet și cu livrare, precum și fiecare vânzare înregistrată la casă, de la cea mai veche — sau, când este setat paidSince, în ordinea în care au fost plătite. O comandă care încă așteaptă plata în avans nu este inclusă.
| Parametru | Type | Înțeles |
|---|---|---|
status |
string | Separate prin virgulă: open, paid. |
source |
string | customer (plasată de oaspete) sau staff (înregistrată de personal). |
fulfilment |
string | Separate prin virgulă: dine_in, takeaway, delivery. |
branchId |
integer | Doar comenzile unei singure locații. |
from |
ISO 8601 datetime | Doar comenzile create la această oră sau după ea. |
to |
ISO 8601 datetime | Doar comenzile create înainte de această oră. |
paidSince |
ISO 8601 datetime | Doar comenzile plătite de la această oră; sortează după paidAt crescător, pentru sincronizarea vânzărilor. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
page |
integer | Numărul paginii, începând de la 1. Valoarea implicită: 1. |
/v1/company/orders/{id}
Doar citire sau citire-scriere
Obține o comandă
O singură comandă, cu liniile, totalurile și atribuirea ei, în forma în care o transmit webhook-urile de comenzi.
/v1/company/loyalty/programs
Doar citire sau citire-scriere
Lista programelor de fidelizare
Fiecare program cu card de ștampile: nume, stare, numărul de ștampile necesare, recompensa și unde se aplică.
/v1/company/loyalty/cards
Doar citire sau citire-scriere
Lista cardurilor de fidelitate
Cardurile membrilor, în forma obiectului de fidelizare. Un membru care și-a umplut cardul îl are marcat ca finalizat și, alături, unul nou, activ; customer.id este membrul.
| Parametru | Type | Înțeles |
|---|---|---|
programId |
integer | Doar un singur program. |
customerId |
integer | Doar un singur membru. |
status |
string | Separate prin virgulă: active, completed. |
updatedSince |
ISO 8601 datetime | Doar cardurile ștampilate sau finalizate de la această oră; sortează după updatedAt crescător. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
page |
integer | Numărul paginii, începând de la 1. Valoarea implicită: 1. |
/v1/company/loyalty/rewards
Doar citire sau citire-scriere
Lista recompenselor de fidelizare
Recompensele obținute prin completarea unui card, cu codul, data de expirare și dacă au fost folosite.
| Parametru | Type | Înțeles |
|---|---|---|
programId |
integer | Doar un singur program. |
customerId |
integer | Doar un singur membru. |
status |
string | Separate prin virgulă: issued, redeemed, expired. |
from |
ISO 8601 datetime | Doar recompensele acordate la această oră sau după ea. |
to |
ISO 8601 datetime | Doar recompensele acordate înainte de această oră. |
limit |
integer | Dimensiunea paginii, 1–100. Valoarea implicită: 50. |
page |
integer | Numărul paginii, începând de la 1. Valoarea implicită: 1. |
/v1/company/webhooks
Doar citire sau citire-scriere
Lista abonărilor la webhook-uri
Abonările create de această cheie. Webhook-urile adăugate în panou nu apar aici.
/v1/company/webhooks
Doar citire sau citire-scriere
Abonează un webhook
Pornește trimiterea evenimentelor către un URL — apelul pe care îl face aplicația unei platforme de automatizare când utilizatorul activează un declanșator. Returnează abonarea și secretul ei de semnare, o singură dată. Corp JSON: {"url": "…", "events": ["order.placed"]}; este acceptat și formatul Zapier {"target_url": "…", "event": "…"}.
| Parametru | Type | Înțeles |
|---|---|---|
url |
string, required | Adresa https către care se trimite (se acceptă și target_url). |
events |
array of strings, required | Tipuri de evenimente, familii precum order.* sau loyalty ori * pentru toate (se acceptă și event, pentru unul singur). |
description |
string | Un nume afișat în panou. Implicit, numele platformei și al cheii. |
/v1/company/webhooks/{id}
Doar citire sau citire-scriere
Dezabonează un webhook
Oprește trimiterea către o abonare creată de această cheie. Returnează 204. Revocarea cheii elimină și toate abonările ei.
Obiectul de rezervare
O rezervare și o programare au aceeași structură: tip, ID, stare, sursă, guestInitiated, startsAt/endsAt/fus orar (fusul orar propriu al sucursalei), monedă, companie, sucursală, oaspete, atribuire, conversionId, createdAt/updatedAt — plus partySize și tabelul pentru o rezervare, serviciul și specialistul pentru o programare. Este exact ceea ce furnizează un webhook, așa că un receptor care gestionează una le gestionează pe amândouă.
{
"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…" }
}
}
Obiectul de comandă
O comandă are aceeași formă oriunde o întâlniți — în REST API, în webhook-urile de comenzi și în fluxul de evenimente: kind ("order"), id, number (numărul pe care îl strigă personalul), status (open sau paid), source (customer sau staff), guestInitiated, fulfilment, table, label, deliveryAddress, note, currency, timezone, company, branch, customer (membrul programului de fidelizare, când personalul l-a identificat), items (name, variant, quantity, unitPriceCents, subtotalCents), itemCount, subtotalCents, discountCents, deliveryFeeCents, tipCents, totalCents, valueCents (valoarea comenzii fără bacșiș — cifra raportată de conversii), paymentMethod, servedBy, conversionId, createdAt, paidAt și attribution. Sumele sunt întotdeauna în subunități monetare.
{
"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…" }
}
}
Obiectul de fidelizare
Fiecare eveniment, card și recompensă de fidelizare are aceeași formă: kind ("loyalty"), id (cardul), timezone, company, branch (locul unde s-a întâmplat, dacă există), program (id, name, stampsRequired, rewardTitle), customer (id, name, phone, locale), card (id, status, stampsCount, stampsRequired, stampsToReward, createdAt), stamp (pentru o ștampilă: source, issuedBy, createdAt) și reward (pentru o recompensă: code, title, status, expiresAt, redeemedAt, redeemedBy), plus conversionId, id-ul sub care este raportată o înscriere la fidelizare.
{
"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…"
}
Flux de evenimente
Fiecare rând are forma { id, cursor, type, createdAt, previousStatus, data }. data conține subiectul sub cheia numită de prefixul evenimentului: data.booking, data.order sau data.loyalty. Păstrați cel mai mare cursor procesat și transmiteți-l înapoi ca after — nu sare și nu repetă niciodată un rând, deci puteți relua în siguranță după o cădere. Ignorați tipurile pe care nu le tratați: pot apărea altele noi.
| Tipul evenimentului | Înțeles |
|---|---|
booking.requested | Un oaspete a cerut o rezervare care așteaptă confirmarea dvs. |
booking.confirmed | O rezervare este confirmată — creată direct ca fiind confirmată sau confirmată ulterior de personal. |
booking.cancelled | Anulată de oaspete sau de local; status arată de cine. |
booking.no_show | Oaspetele nu a venit. |
booking.completed | Vizita s-a încheiat. |
order.placed | Comanda unui oaspete a ajuns la local — de pe pagină, prin codul QR al unei mese, la pachet sau cu livrare; după plată, dacă localul o încasează în avans. |
order.paid | Orice comandă achitată, inclusiv vânzările înregistrate la casă. |
loyalty.member_joined | Un client a primit prima ștampilă într-un program. |
loyalty.stamp_added | O ștampilă a fost adăugată pe un card. |
loyalty.reward_issued | Un card a fost completat și recompensa lui a fost acordată. |
loyalty.reward_redeemed | O recompensă a fost oferită clientului. |
curl "https://api.tapti.me/v1/company/events?after=998&limit=100" \
-H "Authorization: Bearer tt_live_…"
Webhooks
Creați un endpoint în Integrări → Webhook-uri și API — sau conectați Zapier, Make, n8n ori Pipedream în Integrări → Automatizare — ca TapTime să trimită prin POST un eveniment JSON semnat în momentul în care se schimbă o rezervare, o comandă sau un card de fidelitate. Alegeți evenimentele pentru fiecare endpoint. O companie poate avea în total până la 50 de webhook-uri, postback-uri, chaturi și conexiuni de automatizare.
| Antet | Înțeles |
|---|---|
TapTime-Event | Tipul evenimentului, de exemplu booking.confirmed. |
TapTime-Event-Id | Identificatorul stabil al evenimentului — folosiți-l pentru a elimina duplicatele unei livrări repetate. |
TapTime-Delivery | ID-ul acestei încercări de livrare. |
TapTime-Signature | t = <timp Unix>, v1 = <valoare hexazecimală HMAC-SHA256 a lui „t.rawBody”>, semnată cu secretul propriu al punctului terminal. |
- Orice răspuns din seria 2xx este considerat ca fiind livrat; în cazul unui răspuns care nu aparține seriei 2xx sau al unei depășiri a timpului de așteptare, se efectuează o nouă încercare cu interval de așteptare (1 min, 5 min, 15 min, 1 oră, 3 ore, 6 ore, 12 ore), până la un număr maxim de 8 încercări — un cod de stare 410 oprește repetarea încercărilor.
- Redirecționările nu sunt urmate.
- Adresa URL trebuie să fie de tip HTTPS în mediul de producție și nu poate indica o adresă privată sau de loopback.
- Livrarea se efectuează cel puțin o dată: verificați întotdeauna semnătura și eliminați duplicatele la TapTime-Event-Id.
{
"id": "evt_9f3c2a7e1b",
"type": "booking.confirmed",
"createdAt": "2026-09-12T19:02:11+03:00",
"test": false,
"data": { "booking": { "kind": "reservation", "id": 4821, "status": "confirmed", "…": "…" } }
}
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));
Abonări la webhook-uri
Platformele de automatizare activează și dezactivează declanșatoarele prin API, în loc să-i ceară utilizatorului să lipească un URL („REST hooks”): trimiteți prin POST URL-ul propriu al platformei cu evenimentele dorite, păstrați id-ul returnat și ștergeți-l cu DELETE când declanșatorul este oprit. O abonare este un webhook semnat obișnuit — apare în panou, marcată cu cheia care a creat-o.
- O cheie vede și elimină doar abonările pe care le-a creat; revocarea cheii le elimină pe toate.
- Adresele de pe hooks.zapier.com, make.com și pipedream.net sunt recunoscute și afișate cu numele platformei; orice altă adresă https este un webhook obișnuit.
- Secretul de semnare este returnat o singură dată, în răspunsul la POST; proprietarul îl poate afișa din nou în panou.
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"]}'
Postback-uri
O cerere GET sau POST către URL-ul propriu al trackerului dvs., cu macrourile completate, pentru platformele care folosesc postback-uri prin query string în loc de webhook-uri JSON. Pentru o comandă, {value} este valoarea comenzii fără bacșiș, iar {order_id} este id-ul ei.
https://tracker.example/postback
?cid={click_id}&event={event}&status={status}
&payout={value}&cur={currency}
Simboluri de substituție disponibile
{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}
Erori
Fiecare eroare este de tip JSON: { "error": "<code>", "message": "<human-readable>" }.
| Status | eroare | Înțeles |
|---|---|---|
| 401 | unauthorized |
Antetul „Authorization” lipsește, sau cheia este nevalidă sau a fost revocată. |
| 403 | forbidden |
O cheie de tip „doar citire” denumită punct final de scriere (o modificare de stare). |
| 404 | not_found |
Nu există nicio rezervare cu acel ID care să aparțină companiei la care aparține cheia. |
| 409 | conflict |
Modificarea stării ar duce la o rezervare dublă a mesei sau a locului; nu s-a schimbat nimic. |
| 422 | invalid_status |
Valoarea câmpului „status” nu se regăsește printre valorile acceptate pentru acel tip de rezervare. |
| 422 | invalid_type |
Parametrul type al fluxului de evenimente nu denumește niciun tip sau familie de evenimente. |
| 422 | invalid_url |
URL-ul unei abonări nu este o adresă https publică. |
| 429 | rate_limited |
Peste 50 de solicitări pe minut pentru această cheie. Reduceți ritmul și încercați din nou. |
Accesul la API, webhook-urile și integrările de automatizare și chat sunt incluse în fiecare modul — fără costuri suplimentare și fără un plan separat pentru dezvoltatori.
Începe o perioadă de probă gratuită