Documentación
API
Para montar tu propio formulario, con tu diseño y en tu web. Cubre los tres módulos: reclamos —nosotros asignamos el correlativo, generamos la Hoja oficial y enviamos las copias—, reservas —nosotros llevamos el cupo, las mesas y los avisos— y Beneficios —Mi club en tu web, que está más abajo—.
Si lo único que quieres es que se vea con tu marca dentro de tu web,
no necesitas nada de esto: incrusta el formulario hospedado con una línea
de <script> y personalízalo desde el panel.
Antes de empezar
Si armas tu propio formulario, sigues obligado a capturar los campos del formato oficial y a mostrar los textos legales. Si omites alguno, el registro sale defectuoso y la responsabilidad es del proveedor, no nuestra.
Para no copiarlos a mano de un PDF y quedarte desactualizado cuando cambie la norma,
consúltalos con GET /api/v1/schema: devuelve los campos
obligatorios, sus validaciones y los textos que debes mostrar literales. Trae también
captcha.sitekey, que es lo que necesita tu formulario si
va en el navegador.
Si lo que quieres es solo que se vea con tu marca, no necesitas la API: personaliza el formulario hospedado desde el panel.
Desde dónde puedes llamar, y a qué ritmo
Desde donde quieras. No hay lista de servidores permitidos, ni hace falta avisarnos de dónde corre tu aplicación. La única restricción de origen que existe es para las claves de navegador, y por un motivo concreto: esas viajan en el HTML y las lee cualquiera con F12.
sk_live_… · servidor |
No mira el dominio. Funciona desde localhost,
desde tu portátil o desde donde sea
|
pk_live_… · navegador |
Necesita dominios autorizados, y
http://localhost vale como uno más
|
Lo que sí hay es un límite de ritmo, y existe para un caso muy concreto: que un bucle mal escrito registre cien reclamos en un segundo y eso se convierta en cien correos saliendo a nombre de un negocio que no ha hecho nada. El límite protege al cliente, no a nosotros.
Peticiones permitidas
| Qué haces | Por clave sk_ |
Por IP (solo pk_) |
Por clave pk_ |
|---|---|---|---|
| Registrar un reclamo | 60 / min | 10 / min | 600 / min |
| Consultar una constancia | 60 / min | 10 / min | 600 / min |
| Listar reclamos | 60 / min | — | — |
| Leer un reclamo | 120 / min | — | — |
| Crear una reserva | 60 / min | 5 / 10 min | 600 / min |
| Consultar disponibilidad | 120 / min | 30 / min | 600 / min |
| Modificar una reserva | 60 / min | — | — |
| Cancelar una reserva | 30 / min | — | — |
Con una pk_, se cuenta primero la conexión
de quien visita tu web, y lo que frena no gasta el cupo de tu clave, que queda como techo
para todo tu restaurante: quien copie la clave de tu web no puede dejar sin servicio tu
formulario desde su computadora.
Pasado el límite responde 429 con
retry_after_seconds: espera lo que diga y
reintenta. No hace falta avisarnos ni rotar la clave.
Probar sin ensuciar nada
Antes de escribir una línea, crea una clave de pruebas en el panel,
en Integración. Se llama sk_test_… en vez de
sk_live_…, y esa diferencia en el nombre es
deliberada: es lo primero que se lee en una captura de pantalla o en un
curl pegado en un chat.
Por qué importa
Un reclamo no es una fila que se borra. Registrar uno consume un número correlativo que no vuelve, arranca el plazo legal de quince días hábiles, entra en una cadena de integridad que no admite borrado y manda correos a la dirección que hayas puesto. Una reserva de prueba bloquea una mesa toda la noche y el local pierde ese cubierto sin enterarse.
Con una clave de pruebas, nada de eso ocurre.
Qué hace y qué no
| Comprueba todos los campos | Sí, con el mismo validador |
| Devuelve los mismos errores | Sí, mismos códigos y mensajes |
| Dice si la hora estaría libre | Sí, en Reservas |
| Registra el reclamo o la reserva | No |
| Gasta un número de Hoja | No |
| Ocupa una mesa | No |
| Envía correos | No |
| Lee datos reales | No — y es a propósito |
Lo último no es un olvido. Todo el valor de una clave de pruebas es que puedas pegarla en Postman, en un repositorio o en una captura sin pensarlo dos veces. Si además sirviera para volcar nombres, documentos y teléfonos, volvería a ser una credencial que hay que custodiar. Para leer, usa la clave de servidor: leer no rompe nada.
curl -X POST https://app.dbtech.cloud/api/v1/complaints \
-H "Authorization: Bearer sk_test_TU_CLAVE_DE_PRUEBA" \
-H "Content-Type: application/json" \
-d '{
"sede": "miraflores",
"tipo": "reclamo",
"consumidor_nombre": "María Ñahui",
"consumidor_doc_tipo": "DNI",
"consumidor_doc_num": "70112233",
"consumidor_domicilio": "Av. Ejemplo 500, Lima",
"consumidor_email": "maria@ejemplo.pe",
"bien_tipo": "producto",
"bien_descripcion": "Pedido #A-4471",
"monto_reclamado": 79.90,
"detalle": "El pedido llegó incompleto y con el empaque abierto.",
"pedido": "Reposición del producto faltante.",
"consentimiento": true,
"datos_adicionales": { "numero_pedido": "A-4471", "mesa": 12 }
}'
Respuesta 200
{
"modo": "prueba",
"ok": true,
"mensaje": "Los datos son correctos. No se registró nada: esta es una clave
de prueba. Con una clave sk_live_ esta misma petición habría
devuelto 201.",
"sede": "miraflores",
"codigo_ejemplo": "MIR-00000-2026"
}
Cuando todo pase, cambia la clave por la de producción. No cambies nada
más: la petición es idéntica, y en producción esa misma llamada responde
201 con el número de Hoja de verdad.
¿Y probar en local?
No hace falta, y tampoco podrías: el servicio necesita su base de datos, sus claves y su proveedor de correo. La clave de pruebas existe justamente para eso — apuntas a la misma URL de siempre y no ocurre nada irreversible.
Todo lo que hay
| Método | Ruta | Qué hace | Clave |
|---|---|---|---|
| POST | /api/v1/complaints | Registrar un reclamo | cualquiera |
| GET | /api/v1/complaints | Listar el Libro | solo sk_live |
| GET | /api/v1/complaints/{id} | Un expediente completo | solo sk_live |
| POST | /api/v1/complaints/lookup | Buscar por código y documento | cualquiera |
| GET | /api/v1/complaints/{id}/pdf | La Hoja en PDF | cualquiera |
| GET | /api/v1/reservations/availability | Reglas del local y horas libres | cualquiera |
| POST | /api/v1/reservations | Reservar | cualquiera |
| GET | /api/v1/reservations | La agenda de un día | solo sk_live |
| GET | /api/v1/reservations/{id} | Una reserva | solo sk_live |
| PATCH | /api/v1/reservations/{id} | Marcar estado, o reprogramar | solo sk_live |
| DELETE | /api/v1/reservations/{id} | Cancelar (avisa al comensal) | solo sk_live |
| GET | /api/v1/schema | Los campos del formato oficial | cualquiera |
| GET | /api/v1/beneficios/club | Tu club y lo que da cada plan | cualquiera |
| POST | /api/v1/beneficios/club/acceso | El socio pide su código | cualquiera |
| POST | /api/v1/beneficios/club/confirmar | El código, a cambio del pase | cualquiera |
| POST | /api/v1/beneficios/club/socio | Lo suyo, con el pase | cualquiera |
| POST | /api/v1/beneficios/club/qr | Su QR que cambia, con el pase | cualquiera |
| POST | /api/v1/beneficios/club/salir | Cerrar su pase | cualquiera |
| POST | /api/v1/beneficios/club/wallet | Su tarjeta en Google Wallet | cualquiera |
Con una clave de pruebas
| POST /api/v1/complaints | Valida igual. No registra, no gasta número, no envía correo. |
| POST /api/v1/reservations | Valida igual y dice si la hora estaría libre. No ocupa mesa. |
| GET …availability | Funciona igual: no hay datos personales de por medio. |
| GET /api/v1/schema | Funciona igual. |
| Todo lo de leer y gestionar | Responde 403: una clave de pruebas no ve datos reales. |
Un método que una ruta no atiende responde 405 con la
cabecera Allow. Manda siempre
Content-Type: application/json: sin él, la protección
contra envíos de formulario cruzados lo rechaza antes de llegar a la ruta.
Autenticación
Todas las peticiones llevan Authorization: Bearer <clave>.
Las claves se crean en el panel, en Integración.
- sk_live_…
- Servidor a servidor. Sin captcha. Nunca la expongas en el navegador: quien la tenga puede registrar reclamos en tu libro.
- pk_live_…
-
Para el navegador. Exige
turnstile_tokeny solo funciona desde los dominios que declaraste. Sin cabeceraOriginválida se rechaza, aunque la clave sea buena. El captcha se monta en tres líneas: más abajo está el formulario entero.
El proveedor sale de la clave, no del cuerpo: una clave no puede escribir en el libro de otra empresa.
Los bloques que debes capturar
La hoja oficial tiene cuatro secciones. Las tres primeras las llena el consumidor; la cuarta la llena el proveedor al responder, desde el panel o por API.
1 Identificación del consumidor
consumidor_nombre · consumidor_doc_tipo · consumidor_doc_num · consumidor_domicilio · consumidor_telefono · consumidor_email · es_menor_edad · apoderado_nombre
2 Identificación del bien contratado
bien_tipo · bien_descripcion · monto_reclamado · moneda
3 Detalle y pedido
tipo (reclamo | queja) · detalle · pedido
Extra — datos_adicionales
Objeto libre para tus propios campos: número de pedido, mesa, código de reserva. Se guardan y entran en el hash de integridad, pero no aparecen en la hoja oficial porque el formato de INDECOPI no admite campos añadidos. Sí salen en el anexo del PDF.
Registrar un reclamo
POST /api/v1/complaints
curl -X POST https://app.dbtech.cloud/api/v1/complaints \
-H "Authorization: Bearer sk_live_TU_CLAVE" \
-H "Content-Type: application/json" \
-d '{
"sede": "miraflores",
"tipo": "reclamo",
"consumidor_nombre": "María Ñahui",
"consumidor_doc_tipo": "DNI",
"consumidor_doc_num": "70112233",
"consumidor_domicilio": "Av. Ejemplo 500, Lima",
"consumidor_email": "maria@ejemplo.pe",
"bien_tipo": "producto",
"bien_descripcion": "Pedido #A-4471",
"monto_reclamado": 79.90,
"detalle": "El pedido llegó incompleto y con el empaque abierto.",
"pedido": "Reposición del producto faltante.",
"consentimiento": true,
"datos_adicionales": { "numero_pedido": "A-4471", "mesa": 12 }
}'
Respuesta 201
{
"id": "cdbe525a-50fe-41d6-927f-5d5302ed7f23",
"codigo": "MIR-00001-2026",
"correlativo": 1,
"deadline_at": "2026-09-04",
"consulta_url": "https://app.dbtech.cloud/consulta/9771b92f…",
"pdf_url": "https://app.dbtech.cloud/api/v1/complaints/cdbe…/pdf?token=9771…"
}
Guarda el codigo y la
consulta_url: son lo que el consumidor necesita para
seguir su caso. La copia por correo se envía sola.
Buscar una hoja — tu propio buscador
POST /api/v1/complaints/lookup
Para montar el buscador de seguimiento en tu web, con tu diseño. El consumidor teclea su número de hoja y su documento; esto te dice a dónde mandarlo.
curl -X POST https://app.dbtech.cloud/api/v1/complaints/lookup \
-H "Authorization: Bearer pk_live_TU_CLAVE" \
-H "Origin: https://www.tu-restaurante.pe" \
-H "Content-Type: application/json" \
-d '{
"codigo": "MIR-00001-2026",
"doc_num": "70112233",
"turnstile_token": "…"
}'
Respuesta 200
{
"codigo": "MIR-00001-2026",
"consulta_url": "https://app.dbtech.cloud/consulta/9771b92f…",
"pdf_url": "https://app.dbtech.cloud/api/v1/complaints/cdbe…/pdf?token=9771…"
}
Redirige al consumidor a consulta_url.
Cuando el número encaja en varios de tus locales
El correlativo se cuenta por sede, así que cada local tiene su «00001». Si el consumidor solo recuerda el número corto, la respuesta trae con qué preguntarle — y no trae el enlace: la credencial que abre el expediente se entrega cuando no queda duda de cuál es la hoja.
{
"ambiguo": true,
"mensaje": "Ese número existe en más de uno de tus locales. Pregunta en cuál fue.",
"sedes": [
{ "sede": "miraflores", "nombre": "Miraflores" },
{ "sede": "barranco", "nombre": "Barranco" }
]
}
Repite la llamada añadiendo "sede": "barranco".
Dos cosas que conviene saber
No devuelve el expediente, solo el enlace. Meter los datos del reclamo en el HTML de tu web sería una segunda copia de datos personales fuera del registro, en un sitio del que no podemos responder. El buscador es tuyo; el último paso lo servimos nosotros.
Solo busca en tu libro. La empresa sale de tu clave, nunca del cuerpo de la petición: tu buscador no puede resolver la hoja de otro negocio.
Límites: 60 por minuto y clave; con claves publishable, 10 por minuto e IP —contadas antes que la clave, que pasa a ser un techo de 600— porque ahí cada IP es un consumidor, y sin ese freno el buscador sería una forma de probar documentos en serie.
El captcha, en tu formulario
Solo si usas una clave pk_live_. Las
sk_live_ no llevan captcha: viven en tu servidor, donde
no hay nadie a quien comprobar.
Tres cosas distintas, y solo una viaja
- sitekey
- — público y constante. Va escrito en tu HTML y dice qué widget
pintar. Te lo damos en
GET /api/v1/schema, encaptcha.sitekey. - clave secreta
- — nuestra. Verifica contra Cloudflare y no sale de nuestro servidor. Tú no la necesitas.
- token
- — lo genera el widget cada vez que alguien resuelve.
Cientos de caracteres, dura unos 5 minutos y se gasta al primer uso. Esto es lo que
va en
turnstile_token.
Si lo que mandas no cambia entre una petición y la siguiente, es el sitekey y no el
token — y el servidor devolverá 400. Un valor
idéntico para todo el mundo no puede demostrar que tú pasaste el reto.
En tu página
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js"
async defer></script>
<form id="buscar">
<input name="codigo" placeholder="MIR-00001-2026" required>
<input name="doc_num" placeholder="Tu documento" required>
<!-- El widget inyecta aquí dentro un input oculto: cf-turnstile-response -->
<div class="cf-turnstile" data-sitekey="TU_SITEKEY"></div>
<button>Buscar mi reclamo</button>
</form>
Al enviar
document.getElementById('buscar').addEventListener('submit', async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const r = await fetch('https://app.dbtech.cloud/api/v1/complaints/lookup', {
method: 'POST',
headers: {
'Authorization': 'Bearer pk_live_TU_CLAVE',
'Content-Type': 'application/json',
},
body: JSON.stringify({
codigo: fd.get('codigo'),
doc_num: fd.get('doc_num'),
// Ya viene en el FormData: lo puso el widget al resolverse.
turnstile_token: fd.get('cf-turnstile-response'),
}),
});
const data = await r.json();
if (data.consulta_url) location.href = data.consulta_url;
else alert(data.error ?? data.mensaje);
// El token es de UN SOLO USO. Sin esto, la segunda búsqueda da 400.
turnstile.reset();
});
No copies el token a mano ni lo busques en el DOM: el widget deja un
input oculto dentro de tu formulario, así que el
FormData ya lo lleva. Y no pongas la cabecera
Origin: la pone el navegador, y por eso una clave
publishable puede ser pública — la clave se copia, el origen no.
El fallo que se come todo el mundo
Falta turnstile.reset() después de enviar. La primera
búsqueda funciona y la segunda devuelve 400, porque el
widget entrega el mismo token ya gastado. El mensaje dice que la comprobación venció,
y es literal.
Para probar desde Postman, que no es un navegador: abre tu formulario,
deja que el widget se resuelva y en la consola pide
copy(turnstile.getResponse()). Tienes 5 minutos y un
solo envío.
Leer y gestionar
Solo con clave de servidor
Todo lo de esta sección exige sk_live_… y responde
403 a una clave publishable. Aquí salen nombres,
documentos y teléfonos, y se puede anular la mesa de un cliente. Una clave
pk_live_ está pensada para ser pública: la lee
cualquiera con F12. Sirve para meter datos, nunca para sacarlos.
El Libro
GET /api/v1/complaints
Filtros: estado (pendiente · cerrado),
sede, desde y
hasta (AAAA-MM-DD), limit
(1–100, por defecto 25).
Se pagina por cursor, no por número de página: pasa el
siguiente_cursor que devuelve la respuesta. Con
offset, un reclamo nuevo mientras paginas desplaza
todo y hace que se repita una fila y se salte otra. Cuando llega
null, no hay más.
El listado trae lo justo para pintar una bandeja. El documento, el domicilio y el
detalle están en GET /api/v1/complaints/{id}, uno a
uno: repartir cincuenta expedientes enteros por página es multiplicar copias de datos
personales para que uses tres campos.
El detalle no devuelve el consulta_token
—es la llave que abre la constancia sin más comprobación— ni la IP del envío. Sí
devuelve el hash, para que puedas comprobar por tu
cuenta que el expediente no cambió.
La agenda
GET /api/v1/reservations?fecha=AAAA-MM-DD
fecha es obligatoria. Sin ella lo natural sería
devolver «todas», y en un local con dos años de historial eso son decenas de miles de
filas con datos personales por una llamada distraída. Filtros opcionales:
sede y estado.
PATCH /api/v1/reservations/{id}
Hace dos cosas distintas, y por eso no se pueden pedir juntas:
| { "estado": … } |
Marcar. sentada,
no_show o
completada
|
| { "fecha", "hora", "personas" } | Reprogramar. Lo que no mandes se queda como está |
Mandar las dos cosas a la vez responde 422. No es
rigidez: el resultado dependería del orden en que se aplicaran —¿se mueve y luego se
sienta, o se sienta y luego se mueve una reserva ya sentada?— y ese orden no está
definido en ninguna parte. Que lo decida quien llama, en dos peticiones.
La frontera de lo que puedes cambiar no es «reservas sí, reclamos no»: es
si la acción se puede deshacer. Marcar que alguien llegó se corrige
diciendo lo contrario y no sale del local. Cancelar, no — por eso tiene su propio
verbo y no se puede hacer sin querer con un PATCH.
Reprogramar
Cambiar la hora es una cosa; cambiar cuántos son es otra, y las dos van por aquí. Una reserva de dos que pasa a cuatro necesita otra mesa, así que el sistema replanifica desde cero: suelta el cupo viejo y busca sitio para el grupo nuevo. Puede acabar en un tamaño de mesa distinto del que tenía.
Si no cabe, no se mueve nada
Responde 409 con
motivo: "sin_cupo" y la reserva se queda
exactamente donde estaba, con su mesa. La operación es atómica: nunca se queda a
medias, sin horario viejo ni nuevo.
Si mandas la misma fecha, hora y grupo que ya tenía, responde
200 con
"sin_cambios": true y no toca nada.
Al comensal no se le avisa. Es lo mismo que hace el panel cuando reprograma el local: quien mueve una reserva suele estar hablando con él por teléfono, y un correo automático llegaría tarde y contradiciendo lo acordado. Si tu sistema mueve reservas sin hablar con nadie, avísale tú.
Es PATCH y no PUT
porque no se reemplaza el recurso: se cambian los campos que mandas. Un
PUT prometería poder enviar la reserva entera,
incluidos el código y el estado, y eso no es cierto.
DELETE /api/v1/reservations/{id}
Cancela; no borra. La reserva queda como
cancelada y se sigue pudiendo consultar: es lo que
distingue «se canceló» de «nunca existió». Acepta
?motivo=…, en la query y no en el cuerpo, porque un
cuerpo en un DELETE lo descartan muchos proxies sin
avisar.
Manda un correo al comensal, y ese correo no se retira. Cancelar dos
veces es 200 y no avisa dos veces: puedes reintentar
tras un fallo de red sin miedo. Una mesa ya atendida
(completada o no_show)
responde 409: no se anula lo que ya ocurrió.
Sedes
La numeración correlativa es por establecimiento, así que
sede es obligatoria si el proveedor tiene más de uno.
Nunca elegimos una por ti: un reclamo en el libro equivocado deja mal numerados los dos.
Si la omites con varias sedes, la respuesta es 422 con la lista de slugs disponibles.
Reservas
Dos llamadas: preguntar qué hay libre y reservar. El cupo, las mesas, los recordatorios y los avisos al local corren por nuestra cuenta.
Requiere el módulo de Reservas contratado; si no, las dos responden
403.
Qué hay libre
GET /api/v1/reservations/availability
Devuelve las reglas del local —tamaños de grupo, hasta qué fecha se
puede reservar, cuántas horas antes se cancela— y, si mandas
fecha, también las horas libres. Sin
fecha solo las reglas: es la llamada que hace tu
formulario al cargarse.
Pide las reglas en vez de codificarlas a mano. El día que el local cambie su configuración desde el panel, tu formulario se entera; si las escribiste tú, mentirá.
curl "https://app.dbtech.cloud/api/v1/reservations/availability?sede=miraflores&fecha=2026-10-30&personas=4" \
-H "Authorization: Bearer pk_live_TU_CLAVE" \
-H "Origin: https://www.tu-restaurante.pe"
Respuesta 200
{
"sede": "miraflores",
"nombre": "Miraflores",
"acepta_reservas": true,
"grupo_min": 1,
"grupo_max": 8,
"aforo_maximo": 8,
"fecha_min": "2026-09-01",
"fecha_max": "2026-10-31",
"anticipacion_min_horas": 2,
"cancelacion_horas": 2,
"confirmacion_automatica": true,
"fecha": "2026-10-30",
"personas": 4,
"horarios": [
{ "hora": "19:00", "mesas_libres": 3, "mesa": "Mesa para 4", "capacidad": 4 },
{ "hora": "19:30", "mesas_libres": 2, "mesa": "Mesa para 4", "capacidad": 4 }
]
}
Para el selector de comensales, usa aforo_maximo
Son dos límites distintos y el que manda es el menor.
grupo_max es lo que el local admite por política;
aforo_maximo es lo más grande que de verdad cabe
juntando sus mesas. Un local con mesas de cuatro y
grupo_max de 20 puede tener
aforo_maximo de 12 si no tiene más mesas.
Ofrece hasta aforo_maximo: pedir por
encima se rechaza, y ofrecer por debajo te hace perder reservas que el local sí
quería. Si vale 0, la sede no ha declarado mesas y
no puede aceptar a nadie todavía.
Esto es una foto, no una reserva
Nada queda apartado. Entre que pintas las horas y alguien pulsa el botón pueden pasar
minutos, y el cupo lo decide la base de datos al insertar, de forma atómica. Un alta
puede responder sin_cupo aunque esta llamada dijera
que sí — tu formulario tiene que saber recuperarse de eso, volviendo
a pedir las horas.
Si la sede todavía no acepta reservas en línea, responde 200
con acepta_reservas: false — no un error. Así puedes
enseñar «reserva por teléfono» en vez de romperte.
Reservar
POST /api/v1/reservations
curl -X POST https://app.dbtech.cloud/api/v1/reservations \
-H "Authorization: Bearer pk_live_TU_CLAVE" \
-H "Origin: https://www.tu-restaurante.pe" \
-H "Content-Type: application/json" \
-d '{
"sede": "miraflores",
"fecha": "2026-10-30",
"hora": "19:30",
"personas": 4,
"nombre": "Ana Torres",
"telefono": "987654321",
"email": "ana@ejemplo.pe",
"notas": "Alergia a los frutos secos",
"turnstile_token": "…"
}'
Respuesta 201
{
"id": "ab56292a-3730-4c7b-b2e3-58ca0bdfee0f",
"codigo": "MIR-78761D",
"estado": "confirmada",
"sede": "miraflores",
"gestion_url": "https://app.dbtech.cloud/reserva/d39cdebf…"
}
telefono es obligatorio y
email no — al revés que en el Libro. Si el local
necesita avisar de un imprevisto una hora antes, el correo no sirve.
Manda al comensal a gestion_url: ahí ve su reserva y
puede cancelarla. Es la llave — quien tenga el enlace puede cancelar, así que se le
entrega a él y no se publica.
Cuando no se puede
El cuerpo trae motivo, un código estable. Úsalo tú, no
el texto: «esa hora acaba de ocuparse» no se comprueba con un if.
{
"error": "Esa hora acaba de ocuparse. Vuelve a elegir entre las horas disponibles.",
"motivo": "sin_cupo",
"campos": { "hora": ["Esa hora acaba de ocuparse. …"] }
}
| motivo | HTTP | Qué pasó |
|---|---|---|
| sin_cupo | 409 | La mesa se ocupó entre la consulta y el envío. Al reprogramar: no cabe, y la reserva no se movió |
| estado_no_permite | 409 | Al reprogramar: la reserva ya está cancelada, sentada o cerrada |
| horario_no_disponible | 409 | El local no abre a esa hora ese día |
| fecha_fuera_de_rango | 422 | Más allá de la anticipación máxima |
| anticipacion_insuficiente | 422 | Demasiado justo: falta menos de lo que pide el local |
| grupo_fuera_de_rango | 422 | Más o menos comensales de los que admite |
| sede_sin_reservas | 409 | La sede no tiene las reservas en línea activadas |
| sede_inactiva | 404 | La sede no existe o está desactivada |
Límites: 60 altas por minuto y clave. Con claves publishable, 5 cada diez minutos por IP —el mismo tope que el formulario hospedado—, contadas antes que la clave, que pasa a ser un techo de 600. Una reserva falsa no llena una tabla: deja una mesa vacía toda la noche.
Beneficios: el club en tu web
Lo que hace Mi club, para pintarlo con tu diseño: el socio escribe su documento, le llega
un código a su correo, y con el código recibes su pase de 30 minutos.
Con el pase, en el cuerpo de cada llamada, ves lo suyo y su QR que cambia. Requiere el
módulo de Beneficios; si no, 403.
- La respuesta a pedir el código es siempre la misma, sea socio o no: píntala tal cual.
- El pase, en memoria: nunca en
localStorageni en una cookie. Al salir, llama asaliry deja de servir. - El QR vence en
expira_eny es de un solo uso: pide otro antes. - Google Wallet:
walletdevuelve la dirección que guarda el pase; ábrela en otra pestaña. Sin Wallet activado,503. - Con clave
pk_, pedir el código lleva captcha enturnstile_token, y como mucho 5 pedidos cada diez minutos por IP; la base calla al sexto de un mismo socio en la hora. Consk_, ni captcha ni tope por IP: el captcha lo pone tu formulario. - Con una clave de prueba, pedir el código valida y no manda nada; lo demás responde
403.
El paso a paso, con ejemplos, está en la guía de integraciones. Si prefieres no programar,
incrusta Mi club como el formulario: /club/<tu-empresa>?embed=1.
Errores
| Código | Significa |
|---|---|
| 401 | Falta la clave, o es inválida o revocada |
| 403 | Dominio no autorizado para esa clave publishable |
| 404 | Sede inexistente o inactiva |
| 422 | Datos inválidos. El cuerpo trae campos con el detalle |
| 400 | Captcha no verificado (solo claves publishable) |
| 404 | En /lookup: no hay ninguna hoja con ese número y ese documento |
| 429 | Límite de peticiones. Espera lo que diga retry_after_seconds |