Requiply
TypeScript SDK

Bookings

Create booking requests and administer bookings with the Requiply SDK.

bookings.create()

bookings.create(
  input: BookingCreateInput,
  options?: RequiplyRequestOptions,
): Promise<BookingCreateResponse>

Required: startDate, endDate, items (up to 100), and deliveryType (pickup or delivery). A regular booking also needs paymentType; a booking request (asRequest: true) does not. Optional: bundles, services, clientId or inline client details, allowOutsideWorkingHours, adjustment, and saleLines.

paymentType accepts payOnPickup, stripe, wayforpay, monobank, or liqpay. An online method needs an active integration for that provider.

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 needs an email or a phone, and may add name and lastName. It is matched to an existing client by email, then by phone, and created when neither matches. A server integration that already knows the client can pass clientId instead. A booking request does not hold inventory and sets up no payment until staff approve it.

Publishable keys may use this method only for booking requests with asRequest: true. Use a secret key on a trusted server for regular booking creation.

The status the booking starts in comes from the organization's Booking creation settings: Status for booking requests when asRequest is true, Default status for new bookings otherwise. Statuses belong to each organization and can be renamed, so do not hard-code a status name such as Request or New in your integration.

A date-time without an offset, such as 2026-07-01T10:00:00, is read as local time in the organization's timezone, daylight saving included. A value with Z or an offset is used as given. A date with no time, such as 2026-07-01, is read as midnight and usually fails the working-hours check, so always send a time.

startDate and endDate must each fall on a working day inside the organization's working hours, evaluated in the organization timezone. Otherwise the response has success: false, reason: "working_hours", and a message describing the allowed window. A secret key may pass allowOutsideWorkingHours: true to skip that check for a pickup or return the business has agreed to handle outside its schedule. Publishable keys cannot use the flag and receive a 403.

Booking cost adjustment

The REST endpoint POST /api/public/v1/bookings/create also accepts one booking cost adjustment, a one-off discount or surcharge on this booking:

"adjustment": { "type": "percent", "value": -10, "reason": "Returning client" }

type is units (charged days or months), percent (−100 to 100), or amount (organization currency). The value is signed: negative discounts, positive surcharges. Only a secret key may send it, the key's permission group needs Allow booking cost adjustments, and the type must be enabled under the organization's Features. Otherwise the response is a 403 (for example adjustment requires a secret key or Booking adjustments are not enabled for this organization), or a 400 for a zero value without a reason. The same field works on pricing.quote(), so you can show the adjusted price first.

Bundles

Since 0.2.1, bundles: [{ bundleId, quantity }] books whole sets of a bundle, with the IDs from bundles.list(). items may then be empty. The bundle's products are written to the booking as ordinary item lines with the bundle discount applied, and the client discount stacks on top. Sending bundles while the organization has the Bundles feature off answers 403. Quote the same bundles with pricing.quote() first to show bundleDiscountAmount.

Goods for sale

With the Sales feature on, saleLines: [{ saleItemId, quantity }] sells goods together with the booking, at their catalog price. A publishable key can add them to a booking request only while the organization sells to customers, and never beyond the stock on hand. The goods total is added to totalCost, the stock drops when the booking is created, and it comes back if the booking is cancelled. See Sales and Goods for Sale.

Publishable booking requests cannot include supplier-sourced subrental product IDs. Secret-key booking creation can include them when the organization has enabled Subrentals; each selected product creates a snapshotted procurement line instead of assigning an owned inventory unit.

Handling the response

bookings.create() returns one of two shapes, told apart by success. A booking the organization cannot accept does not throw: it resolves with success: false. TypeScript only lets you read reservationId after checking 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: internal ID, for bookings.get().message: why the booking was refused, for example the items are not available for those dates.
reservationOrgId: the booking number staff see in the app.reason: working_hours or minimum_duration when a booking rule was broken; absent for other refusals such as availability.
isRequest: true for a booking request.minimumDuration: details of a minimum_duration refusal, see below.
paymentUrl or paymentRedirect: where to send the customer for an online payment. A post_form redirect includes form fields.

Both shapes include totalCost and currency. Invalid input, such as a missing field or an unknown product, still throws a RequiplyError.

Minimum booking duration

endDate must be after startDate (otherwise 400 endDate must be after startDate), and the booking must be at least the Minimum booking duration from the organization's Booking duration settings (24 hours unless changed). A shorter booking is refused with success: false, reason: "minimum_duration", and a minimumDuration object you can use to offer a valid return:

{
  "success": false,
  "reason": "minimum_duration",
  "message": "...",
  "minimumDuration": {
    "minimumDurationMinutes": 1440,
    "requestedDurationMinutes": 240,
    "earliestReturn": "2026-10-07T10:00",
    "timeZone": "Europe/Kyiv"
  }
}

earliestReturn is the earliest return accepted for that pickup, as local time (YYYY-MM-DDTHH:mm) in timeZone. Durations are measured on the organization's local clock, so a daylight-saving change does not make a booking shorter or longer.

bookings.list()

bookings.list(
  params?: BookingListParams,
  options?: RequiplyRequestOptions,
): Promise<BookingListResponse>

This is a secret-key server operation. Bookings come newest first, by creation time. Optional filters:

ParameterEffect
dateFrom, dateToBookings whose pickup (startDate) falls in the range. A bare date is midnight, so dateTo: '2026-07-31' leaves out pickups later on 31 July; pass '2026-07-31T23:59:59' or the next day.
createdFrom, createdToBookings created in the range. Useful for syncing new bookings since the last run.
statusOne status name, or several separated by commas, case-insensitive. Statuses belong to each organization, so read the names from your own app. An unknown name returns an empty list.
clientIdOne client's bookings.
limit, cursorPage size (1 to 200, default 50) and the nextCursor of the previous page.
const page = await requiply.bookings.list({
  dateFrom: '2026-07-01',
  dateTo: '2026-07-31',
  limit: 25,
});

The response includes bookings, currency, and nextCursor: string | null. Status, client, total-cost, and organization reservation fields on list items can be null.

bookings.get()

bookings.get(
  id: number,
  params?: { idKind?: 'internal' | 'org' },
  options?: RequiplyRequestOptions,
): Promise<BookingDetailResponse>

Use idKind: 'org' when id is the organization-facing reservation number. Otherwise omit it or use internal.

const { booking } = await requiply.bookings.get(1042, { idKind: 'org' });

The booking includes items, services, and payments. Several status, client, price, provider, and payment URL fields can be null. items lists the booked quantity of each product, even when units are only assigned at pickup.

saleItems lists goods sold with the booking and saleId points to their sale. Both are empty or null when nothing was sold or the Sales feature is off. The goods total is always inside 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 is up to 4000 characters. The note is internal: staff see it on the booking, the client never does. The response contains noteId, reservationId, and nullable createdAt. This is a secret-key server operation.

Copyright © 2026