Documentación para desarrolladores

API REST de TapTime

Consulta y actualiza reservas de mesa y citas, lee pedidos y tarjetas de fidelización, recorre el feed ordenado de eventos y recibe webhooks firmados, desde tu propio CRM, TPV, almacén de datos o una plataforma de automatización. Esta página es la referencia completa; la guía de seguimiento de conversiones explica para qué usarla.

URL basehttps://api.tapti.me AutenticaciónBearer token FormatoJSON Para qué usarla

Cada petición necesita una clave de API de la empresa (Integraciones → Webhooks y API en el panel) enviada como Authorization: Bearer tt_live_…. Las respuestas y los errores son JSON.

Reservas confirmadas modificadas desde una fecha
curl "https://api.tapti.me/v1/company/reservations?status=confirmed&updatedSince=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer tt_live_…"

Autenticación

Cada petición lleva una clave de API de la empresa como token bearer. Créala desde el panel, en Integraciones → Webhooks y API → Claves de la API REST, donde se muestra una sola vez y se guarda en el servidor únicamente como hash SHA-256; una clave perdida se revoca y se sustituye, no se recupera. Una empresa puede tener hasta 10 claves activas.

  • Las claves de solo lectura pueden llamar a todos los endpoints GET y suscribir y cancelar webhooks: una suscripción no envía nada que la clave no pudiera leer ya.
  • Las claves de lectura y escritura también pueden hacer POST para cambiar el estado de una reserva; una clave de solo lectura recibe 403 Forbidden en esas rutas.
  • Una clave pertenece a una sola empresa: cada listado y consulta ya está limitado a ella, no existe un parámetro companyId.

Límites de peticiones

50 peticiones por minuto y por clave, en ventana deslizante, compartidas por todos los endpoints. Si te pasas, recibes 429 Too Many Requests; espera y vuelve a intentarlo en lugar de consultar más rápido, o suscribe un webhook y deja de consultar.

Endpoints

GET /v1/company Solo lectura o lectura y escritura

Obtener la empresa actual

La empresa a la que pertenece la clave y lo que la propia clave puede hacer.

GET /v1/company/reservations Solo lectura o lectura y escritura

Listar reservas

Reservas de mesa de la empresa, de la hora de inicio más antigua a la más reciente; o, si se indica updatedSince, de la modificación más antigua a la más reciente.

ParámetroTipoSignificado
status cadena Separados por comas: pending, confirmed, seated, completed, no_show, cancelled. cancelled incluye los dos motivos de cancelación.
branchId entero Limita a un local.
from fecha y hora ISO 8601 Solo reservas que empiezan en este momento o después (UTC si no se indica desfase).
to fecha y hora ISO 8601 Solo reservas que empiezan antes de este momento.
updatedSince fecha y hora ISO 8601 Solo reservas modificadas desde este momento; cambia el orden a updatedAt ascendente, para sincronizar.
limit entero Tamaño de página, 1–100. Por defecto, 50.
page entero Número de página empezando por 1. Por defecto, 1.
GET /v1/company/appointments Solo lectura o lectura y escritura

Listar citas

Misma estructura y filtros que las reservas, para el módulo de Citas.

ParámetroTipoSignificado
status cadena Separados por comas: pending, confirmed, completed, no_show, cancelled.
branchId entero Limita a un local.
from fecha y hora ISO 8601 Solo citas que empiezan en este momento o después.
to fecha y hora ISO 8601 Solo citas que empiezan antes de este momento.
updatedSince fecha y hora ISO 8601 Solo citas modificadas desde este momento; ordena por updatedAt ascendente.
limit entero Tamaño de página, 1–100. Por defecto, 50.
page entero Número de página empezando por 1. Por defecto, 1.
GET /v1/company/reservations/{id} Solo lectura o lectura y escritura

Obtener una reserva

Una reserva, con la misma estructura con la que la envían los webhooks, incluida su atribución. 404 si el id no pertenece a la empresa de la clave.

GET /v1/company/appointments/{id} Solo lectura o lectura y escritura

Obtener una cita

Una cita, con la misma estructura y las mismas reglas que la consulta de una reserva.

POST /v1/company/reservations/{id}/status Únicamente lectura y escritura

Cambiar el estado de una reserva

Confirmar, sentar, completar, marcar como no presentado, cancelar o reabrir: dispara los mismos webhooks y conversiones que cambiarlo en el cuadrante. Cuerpo JSON: {"status": "..."}.

ParámetroTipoSignificado
status cadena, obligatorio Uno de: pending, confirmed, seated, completed, no_show, cancelled (también se aceptan canceled y canceled_by_venue).
POST /v1/company/appointments/{id}/status Únicamente lectura y escritura

Cambiar el estado de una cita

Igual que el endpoint de reservas, sin el estado seated.

ParámetroTipoSignificado
status cadena, obligatorio Uno de: pending, confirmed, completed, no_show, cancelled (también se aceptan canceled y canceled_by_venue).
GET /v1/company/events Solo lectura o lectura y escritura

Consultar el feed de eventos

Cada evento de reservas, pedidos y fidelización, del más antiguo al más reciente: el mismo feed del que salen los webhooks. Pasa el último cursor que viste como after para obtener solo lo nuevo, y type para obtener solo algunos tipos.

ParámetroTipoSignificado
after cursor entero El cursor del último evento que procesaste. Omítelo para empezar desde el principio.
type cadena Tipos o familias de eventos separados por comas: booking.confirmed,order.placed, u order, loyalty.*. Omítelo para recibir todos los eventos.
limit entero Tamaño de página, 1–100. Por defecto, 50.
GET /v1/company/orders Solo lectura o lectura y escritura

Listar pedidos

Pedidos de mesa, para llevar y a domicilio de los clientes y cada venta registrada en caja, del más antiguo al más reciente; o, si se indica paidSince, en el orden en que se pagaron. Un pedido que sigue esperando su pago por adelantado no se incluye.

ParámetroTipoSignificado
status cadena Separados por comas: open, paid.
source cadena customer (lo hizo el cliente) o staff (lo registró el personal).
fulfilment cadena Separados por comas: dine_in, takeaway, delivery.
branchId entero Limita a un local.
from fecha y hora ISO 8601 Solo pedidos creados en este momento o después.
to fecha y hora ISO 8601 Solo pedidos creados antes de este momento.
paidSince fecha y hora ISO 8601 Solo pedidos pagados desde este momento; ordena por paidAt ascendente, para sincronizar ventas.
limit entero Tamaño de página, 1–100. Por defecto, 50.
page entero Número de página empezando por 1. Por defecto, 1.
GET /v1/company/orders/{id} Solo lectura o lectura y escritura

Obtener un pedido

Un pedido con sus líneas, totales y atribución, con la misma estructura con la que lo envían los webhooks de pedidos.

GET /v1/company/loyalty/programs Solo lectura o lectura y escritura

Listar programas de fidelización

Cada programa de tarjeta de sellos: nombre, estado, sellos necesarios, la recompensa y dónde se aplica.

GET /v1/company/loyalty/cards Solo lectura o lectura y escritura

Listar tarjetas de fidelización

Las tarjetas de los miembros, con la estructura del objeto fidelización. Un miembro que completó una tarjeta la tiene en estado completed y otra nueva activa a su lado; customer.id es el miembro.

ParámetroTipoSignificado
programId entero Limita a un programa.
customerId entero Limita a un miembro.
status cadena Separados por comas: active, completed.
updatedSince fecha y hora ISO 8601 Solo tarjetas selladas o completadas desde este momento; ordena por updatedAt ascendente.
limit entero Tamaño de página, 1–100. Por defecto, 50.
page entero Número de página empezando por 1. Por defecto, 1.
GET /v1/company/loyalty/rewards Solo lectura o lectura y escritura

Listar recompensas de fidelización

Recompensas obtenidas al completar una tarjeta, con su código, su caducidad y si se canjearon.

ParámetroTipoSignificado
programId entero Limita a un programa.
customerId entero Limita a un miembro.
status cadena Separados por comas: issued, redeemed, expired.
from fecha y hora ISO 8601 Solo recompensas emitidas en este momento o después.
to fecha y hora ISO 8601 Solo recompensas emitidas antes de este momento.
limit entero Tamaño de página, 1–100. Por defecto, 50.
page entero Número de página empezando por 1. Por defecto, 1.
GET /v1/company/webhooks Solo lectura o lectura y escritura

Listar suscripciones de webhooks

Las suscripciones que creó esta clave. Los webhooks añadidos en el panel no aparecen aquí.

POST /v1/company/webhooks Solo lectura o lectura y escritura

Suscribir un webhook

Empieza a enviar eventos a una URL: es lo que llama la app de una plataforma de automatización cuando un usuario activa un disparador. Devuelve la suscripción y su secreto de firma, una sola vez. Cuerpo JSON: {"url": "…", "events": ["order.placed"]}; también se acepta el formato de Zapier {"target_url": "…", "event": "…"}.

ParámetroTipoSignificado
url cadena, obligatorio La dirección https a la que enviar (también se acepta target_url).
events array de cadenas, obligatorio Tipos de evento, familias como order.* o loyalty, o * para todo (también se acepta event, para uno solo).
description cadena Un nombre que se muestra en el panel. Por defecto, la plataforma y el nombre de la clave.
DELETE /v1/company/webhooks/{id} Solo lectura o lectura y escritura

Cancelar la suscripción de un webhook

Deja de enviar a una suscripción que creó esta clave. Devuelve 204. Revocar la clave también elimina todas sus suscripciones.

El objeto reserva

Una reserva de mesa y una cita salen con una misma estructura compartida: kind, id, status, source, guestInitiated, startsAt/endsAt/timezone (la zona horaria del propio local), currency, company, branch, guest, attribution, conversionId, createdAt/updatedAt, más partySize y table en una reserva, y service y specialist en una cita. Es exactamente lo que entrega un webhook, así que un receptor que gestiona una gestiona las dos.

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

El objeto pedido

Un pedido tiene la misma estructura dondequiera que lo encuentres (la API REST, los webhooks de pedidos, el feed de eventos): kind ("order"), id, number (el número que canta el personal), status (open o paid), source (customer o staff), guestInitiated, fulfilment, table, label, deliveryAddress, note, currency, timezone, company, branch, customer (el miembro de fidelización, cuando el personal lo identificó), items (name, variant, quantity, unitPriceCents, subtotalCents), itemCount, subtotalCents, discountCents, deliveryFeeCents, tipCents, totalCents, valueCents (lo que vale el pedido sin la propina: la cifra que reportan las conversiones), paymentMethod, servedBy, conversionId, createdAt, paidAt y attribution. Los importes siempre van en unidades menores.

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

El objeto fidelización

Cada evento, tarjeta y recompensa de fidelización comparte una estructura: kind ("loyalty"), id (la tarjeta), timezone, company, branch (dónde ocurrió, cuando lo hay), program (id, name, stampsRequired, rewardTitle), customer (id, name, phone, locale), card (id, status, stampsCount, stampsRequired, stampsToReward, createdAt), stamp (en un sello: source, issuedBy, createdAt) y reward (en una recompensa: code, title, status, expiresAt, redeemedAt, redeemedBy), más conversionId, el id con el que se reporta un alta en fidelización.

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

Feed de eventos

Cada fila es { id, cursor, type, createdAt, previousStatus, data }. data contiene el objeto bajo la clave que indica el prefijo del evento: data.booking, data.order o data.loyalty. Guarda el cursor más alto que hayas procesado y devuélvelo como after: nunca se salta ni repite una fila, así que es seguro reanudar tras un fallo. Ignora los tipos que no gestiones: pueden añadirse otros nuevos.

Tipo de eventoSignificado
booking.requestedUn cliente ha pedido una reserva que espera tu confirmación.
booking.confirmedUna reserva está confirmada: creada ya confirmada o confirmada después por el personal.
booking.cancelledCancelada por el cliente o por el local; status indica quién.
booking.no_showEl cliente no se presentó.
booking.completedLa visita ha terminado.
order.placedEl pedido de un cliente ha llegado al local, desde la página, el código QR de una mesa, para llevar o a domicilio; después del pago cuando el local cobra por adelantado.
order.paidCualquier pedido liquidado, incluidas las ventas registradas en caja.
loyalty.member_joinedUn cliente ha recibido su primer sello en un programa.
loyalty.stamp_addedSe ha añadido un sello a una tarjeta.
loyalty.reward_issuedSe ha completado una tarjeta y se ha emitido su recompensa.
loyalty.reward_redeemedSe ha entregado una recompensa.
Mantente sincronizado con el feed de eventos
curl "https://api.tapti.me/v1/company/events?after=998&limit=100" \
  -H "Authorization: Bearer tt_live_…"

Webhooks

Crea un endpoint en Integraciones → Webhooks y API (o conecta Zapier, Make, n8n o Pipedream en Integraciones → Automatización) para que TapTime envíe por POST un evento JSON firmado en el momento en que cambia una reserva, un pedido o una tarjeta de fidelización. Tú eliges los eventos de cada endpoint. Una empresa puede tener hasta 50 webhooks, postbacks, chats y conexiones de automatización en total.

CabeceraSignificado
TapTime-EventEl tipo de evento, p. ej. booking.confirmed.
TapTime-Event-IdId estable del evento: úsalo para descartar duplicados de un envío reintentado.
TapTime-DeliveryId de este intento de envío concreto.
TapTime-Signaturet=<unix time>,v1=<hex HMAC-SHA256 de "t.rawBody">, firmado con el secreto propio del endpoint.
  • Cualquier respuesta 2xx se considera entregada; una respuesta que no sea 2xx o un tiempo de espera agotado se reintenta con espera progresiva (1 min, 5 min, 15 min, 1 h, 3 h, 6 h, 12 h) hasta 8 intentos; un 410 detiene los reintentos.
  • No se siguen las redirecciones.
  • La URL debe ser HTTPS en producción y no puede apuntar a una dirección privada o de loopback.
  • La entrega es al menos una vez: verifica siempre la firma y descarta duplicados por 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", "…": "…" } }
}
Verificar la firma (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));

Suscripciones de webhooks

Las plataformas de automatización activan y desactivan disparadores a través de la API en lugar de pedir al usuario que pegue una URL («REST hooks»): haz POST con la URL propia de la plataforma y los eventos que quiere, guarda el id devuelto y haz DELETE cuando se desactive el disparador. Una suscripción es un webhook firmado normal: aparece en el panel, marcada con la clave que la creó.

  • Una clave solo ve y elimina las suscripciones que creó; revocar la clave las elimina todas.
  • Las direcciones de hooks.zapier.com, make.com y pipedream.net se reconocen y se muestran con el nombre de la plataforma; cualquier otra dirección https es un webhook normal.
  • El secreto de firma se devuelve una sola vez, en la respuesta al POST; el propietario puede volver a verlo en el panel.
Suscribir una URL a los nuevos pedidos
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"]}'

Postbacks

Un GET o POST a la URL propia de tu tracker con las macros rellenadas, para plataformas que trabajan con postbacks por query string en lugar de webhooks JSON. En un pedido, {value} es el valor del pedido sin la propina y {order_id} su id.

URL de postback con marcadores · GET o POST
https://tracker.example/postback
  ?cid={click_id}&event={event}&status={status}
  &payout={value}&cur={currency}

Marcadores disponibles

  • {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}

Errores

Todos los errores son JSON: { "error": "<code>", "message": "<texto legible>" }.

EstadoerrorSignificado
401 unauthorized Falta la cabecera Authorization o la clave no es válida o ha sido revocada.
403 forbidden Una clave de solo lectura ha llamado a un endpoint de escritura (un cambio de estado).
404 not_found Ninguna reserva con ese id pertenece a la empresa de la clave.
409 conflict El cambio de estado provocaría una doble reserva de la mesa o del hueco; no se ha cambiado nada.
422 invalid_status El valor de status del cuerpo no es uno de los aceptados para ese tipo de reserva.
422 invalid_type El parámetro type del feed de eventos no corresponde a ningún tipo ni familia de eventos.
422 invalid_url La URL de una suscripción no es una dirección https pública.
429 rate_limited Más de 50 peticiones en un minuto para esta clave. Reduce el ritmo y vuelve a intentarlo.
¿Necesitas una clave?

El acceso a la API, los webhooks y las integraciones de automatización y chat se incluyen con cada módulo: sin coste adicional ni plan aparte para desarrolladores.

Empieza la prueba gratuita