Documentație pentru dezvoltatori

API REST TapTime

Citiți și actualizați rezervările de mese și programările, citiți comenzile și cardurile de fidelitate, interogați fluxul ordonat de evenimente și primiți webhook-uri semnate — din propriul CRM, POS, depozit de date sau dintr-o platformă de automatizare. Această pagină este referința completă; ghidul de urmărire a conversiilor explică de ce ați avea nevoie de ea.

URL de bazăhttps://api.tapti.me AuthBearer token FormatJSON De ce să-l folosești?

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.

Rezervările confirmate modificate după o anumită dată
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

GET /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.

GET /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.

ParametruTypeÎ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.
GET /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”.

ParametruTypeÎ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.
GET /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.

GET /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.

POST /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": "..."}.

ParametruTypeÎ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”).
POST /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”.

ParametruTypeÎ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”).
GET /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.

ParametruTypeÎ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.
GET /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ă.

ParametruTypeÎ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.
GET /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.

GET /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ă.

GET /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.

ParametruTypeÎ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.
GET /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.

ParametruTypeÎ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.
GET /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.

POST /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": "…"}.

ParametruTypeÎ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.
DELETE /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ă.

GET /v1/company/reservations/4821 → date
{
  "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.

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…" }
  }
}

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.

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…"
}

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.requestedUn oaspete a cerut o rezervare care așteaptă confirmarea dvs.
booking.confirmedO rezervare este confirmată — creată direct ca fiind confirmată sau confirmată ulterior de personal.
booking.cancelledAnulată de oaspete sau de local; status arată de cine.
booking.no_showOaspetele nu a venit.
booking.completedVizita s-a încheiat.
order.placedComanda 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.paidOrice comandă achitată, inclusiv vânzările înregistrate la casă.
loyalty.member_joinedUn client a primit prima ștampilă într-un program.
loyalty.stamp_addedO ștampilă a fost adăugată pe un card.
loyalty.reward_issuedUn card a fost completat și recompensa lui a fost acordată.
loyalty.reward_redeemedO recompensă a fost oferită clientului.
Rămâi la curent cu noutățile despre eveniment
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-EventTipul evenimentului, de exemplu booking.confirmed.
TapTime-Event-IdIdentificatorul stabil al evenimentului — folosiți-l pentru a elimina duplicatele unei livrări repetate.
TapTime-DeliveryID-ul acestei încercări de livrare.
TapTime-Signaturet = <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.
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", "…": "…" } }
}
Verificarea semnăturii (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));

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.
Abonați un URL la comenzile noi
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.

URL de postback cu substituenți · GET sau POST
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>" }.

StatuseroareÎ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.
Ai nevoie de o cheie?

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ă