Reservas
bookings.create()
bookings.create(
input: BookingCreateInput,
options?: RequiplyRequestOptions,
): Promise<BookingCreateResponse>
Obligatorios: startDate, endDate, items (hasta 100) y deliveryType (pickup o delivery). Una reserva normal también necesita paymentType; una solicitud de reserva (asRequest: true), no. Opcionales: bundles, services, clientId o los datos del cliente en client, allowOutsideWorkingHours, adjustment y saleLines.
paymentType acepta payOnPickup, stripe, wayforpay, monobank o liqpay. Un método online necesita una integración activa para esa pasarela.
const result = await requiply.bookings.create({
startDate: '2026-07-01T10:00:00',
endDate: '2026-07-03T18:00:00',
items: [{ groupId: cameraKitId, quantity: 1 }],
deliveryType: 'pickup',
asRequest: true,
client: { name: 'Alex', email: 'customer@example.com' },
});
client necesita un email o un phone, y puede añadir name y lastName. Se busca un cliente existente por email y, después, por teléfono, y se crea uno nuevo cuando no coincide ninguno. Una integración de servidor que ya conoce al cliente puede pasar clientId en su lugar. Una solicitud de reserva no bloquea inventario ni prepara ningún pago hasta que el personal la aprueba.
asRequest: true. Usa una clave secreta en un servidor de confianza para crear reservas normales.El estado inicial de la reserva viene de los ajustes de creación de reservas de la organización: Status for booking requests (estado de las solicitudes de reserva) cuando asRequest es true y Default status for new bookings (estado por defecto de las reservas nuevas) en caso contrario. Los estados son de cada organización y se pueden renombrar, así que no escribas en tu integración un nombre de estado fijo como Request o New.
Una fecha y hora sin desfase horario, como 2026-07-01T10:00:00, se interpreta como hora local en la zona horaria de la organización, con el horario de verano incluido. Un valor con Z o con desfase se usa tal cual. Una fecha sin hora, como 2026-07-01, se interpreta como medianoche y normalmente no pasa la comprobación del horario, así que envía siempre una hora.
Tanto startDate como endDate deben caer en un día laborable dentro del horario de la organización, evaluado en su zona horaria. Si no, la respuesta tiene success: false, reason: "working_hours" y un mensaje que describe la franja permitida. Una clave secreta puede pasar allowOutsideWorkingHours: true para saltarse esa comprobación en una recogida o una devolución que el negocio ha aceptado atender fuera de su horario. Las claves publicables no pueden usar esta opción y reciben un 403.
Ajuste del coste de la reserva
El endpoint REST POST /api/public/v1/bookings/create también acepta un ajuste del coste de la reserva, un descuento o un recargo puntual en esta reserva:
"adjustment": { "type": "percent", "value": -10, "reason": "Returning client" }
type es units (días o meses cobrados), percent (de −100 a 100) o amount (en la moneda de la organización). El valor lleva signo: negativo para descuentos, positivo para recargos. Solo lo puede enviar una clave secreta, el grupo de permisos de la clave necesita Allow booking cost adjustments (permitir ajustes del coste de la reserva) y el tipo tiene que estar activado en las funciones de la organización. Si no, la respuesta es un 403 (por ejemplo adjustment requires a secret key o Booking adjustments are not enabled for this organization), o un 400 si el valor es cero y no hay motivo. El mismo campo funciona en pricing.quote(), así que puedes mostrar antes el precio ajustado.
Packs
Desde la 0.2.1, bundles: [{ bundleId, quantity }] reserva packs completos de un pack, con los ID de bundles.list(). En ese caso, items puede estar vacío. Los productos del pack se guardan en la reserva como líneas de artículo normales con el descuento del pack aplicado, y el descuento del cliente se suma encima. Enviar packs cuando la organización tiene desactivada la función de packs responde 403. Calcula antes un presupuesto con los mismos bundles en pricing.quote() para mostrar bundleDiscountAmount.
Productos en venta
Con la función de ventas activada, saleLines: [{ saleItemId, quantity }] vende productos junto con la reserva, a su precio de catálogo. Una clave publicable solo puede añadirlos a una solicitud de reserva mientras la organización vende a los clientes, y nunca por encima del stock disponible. El total de los productos se suma a totalCost, el stock baja al crear la reserva y se recupera si la reserva se cancela. Consulta Ventas y productos en venta.
Las solicitudes de reserva con clave publicable no pueden incluir ID de productos de subalquiler de proveedores. La creación de reservas con clave secreta sí puede incluirlos cuando la organización ha activado los subalquileres; cada producto seleccionado crea una línea de aprovisionamiento con una copia fija de sus datos en lugar de asignar una unidad del inventario propio.
Gestionar la respuesta
bookings.create() devuelve una de dos estructuras, que se distinguen por success. Una reserva que la organización no puede aceptar no lanza una excepción: se resuelve con success: false. TypeScript solo te deja leer reservationId después de comprobar success.
if (result.success) {
console.log('Booking', result.reservationOrgId, result.isRequest);
if (result.paymentUrl) redirectTo(result.paymentUrl);
} else {
console.log(result.message, result.reason);
}
success: true (BookingCreated) | success: false (BookingRefused) |
|---|---|
reservationId: el ID interno, para bookings.get(). | message: por qué se ha rechazado la reserva, por ejemplo porque los artículos no están disponibles en esas fechas. |
reservationOrgId: el número de reserva que ve el personal en la app. | reason: working_hours o minimum_duration cuando no se ha cumplido una regla de reserva; no aparece en otros rechazos, como los de disponibilidad. |
isRequest: true en una solicitud de reserva. | minimumDuration: los detalles de un rechazo minimum_duration (más abajo). |
paymentUrl o paymentRedirect: adónde enviar al cliente para un pago online. Una redirección post_form incluye los fields del formulario. |
Las dos estructuras incluyen totalCost y currency. Los datos de entrada no válidos, como un campo que falta o un producto desconocido, siguen lanzando un RequiplyError.
Duración mínima de la reserva
endDate debe ser posterior a startDate (si no, 400 endDate must be after startDate), y la reserva debe durar al menos la Minimum booking duration (duración mínima de la reserva) definida en los ajustes de duración de la reserva de la organización (24 horas salvo que se haya cambiado). Una reserva más corta se rechaza con success: false, reason: "minimum_duration" y un objeto minimumDuration que puedes usar para ofrecer una devolución válida:
{
"success": false,
"reason": "minimum_duration",
"message": "...",
"minimumDuration": {
"minimumDurationMinutes": 1440,
"requestedDurationMinutes": 240,
"earliestReturn": "2026-10-07T10:00",
"timeZone": "Europe/Kyiv"
}
}
earliestReturn es la devolución más temprana que se acepta para esa recogida, como hora local (YYYY-MM-DDTHH:mm) en timeZone. Las duraciones se miden con el reloj local de la organización, así que un cambio de horario de verano no hace que una reserva sea más corta ni más larga.
bookings.list()
bookings.list(
params?: BookingListParams,
options?: RequiplyRequestOptions,
): Promise<BookingListResponse>
Es una operación de servidor con clave secreta. Las reservas salen de la más reciente a la más antigua, por fecha de creación. Filtros opcionales:
| Parámetro | Efecto |
|---|---|
dateFrom, dateTo | Las reservas cuya recogida (startDate) cae en el intervalo. Una fecha sola es medianoche, así que dateTo: '2026-07-31' deja fuera las recogidas posteriores del 31 de julio; pasa '2026-07-31T23:59:59' o el día siguiente. |
createdFrom, createdTo | Las reservas creadas en el intervalo. Útil para sincronizar las reservas nuevas desde la última ejecución. |
status | Un nombre de estado, o varios separados por comas, sin distinguir mayúsculas de minúsculas. Los estados son de cada organización, así que toma los nombres de tu propia app. Un nombre desconocido devuelve una lista vacía. |
clientId | Las reservas de un cliente. |
limit, cursor | El tamaño de página (de 1 a 200, por defecto 50) y el nextCursor de la página anterior. |
const page = await requiply.bookings.list({
dateFrom: '2026-07-01',
dateTo: '2026-07-31',
limit: 25,
});
La respuesta incluye bookings, currency y nextCursor: string | null. Los campos de estado, cliente, coste total y número de reserva de la organización de los elementos de la lista pueden ser null.
bookings.get()
bookings.get(
id: number,
params?: { idKind?: 'internal' | 'org' },
options?: RequiplyRequestOptions,
): Promise<BookingDetailResponse>
Usa idKind: 'org' cuando id es el número de reserva que ve la organización. Si no, omítelo o usa internal.
const { booking } = await requiply.bookings.get(1042, { idKind: 'org' });
La reserva incluye los artículos, los servicios y los pagos. Varios campos de estado, cliente, precio, pasarela y URL de pago pueden ser null. items lista la cantidad reservada de cada producto, incluso cuando las unidades solo se asignan en la recogida.
saleItems lista los productos vendidos con la reserva y saleId apunta a su venta. Los dos están vacíos o son null cuando no se vendió nada o la función de ventas está desactivada. El total de los productos vendidos siempre está incluido en totalCost.
bookings.addNote()
bookings.addNote(
id: number,
content: string,
options?: RequiplyRequestOptions,
): Promise<BookingNoteResponse>
const note = await requiply.bookings.addNote(42, 'Customer confirmed pickup time.');
content admite hasta 4000 caracteres. La nota es interna: el personal la ve en la reserva y el cliente nunca. La respuesta contiene noteId, reservationId y createdAt, que puede ser nulo. Es una operación de servidor con clave secreta.