- Send a request
- How the schema works
- Operations
- Examples
- Today's check-outs, then send one with its serial numbers
- Block dates for maintenance, then free them
- A booking with its serial numbers, moves and order
- Orders with a rental next week
- Rotate your own key
- Quote a stay by the night
- Move stock between locations
- Can we deliver to this postcode, and what is on the run sheet
- End a subscription and record a payment
The GraphQL API gives your systems one address for everything in Rentals & Bookings. You ask for exactly the fields you need, and several things can come back in one request. This page shows how to send a request and lists every query and mutation of Rentals & Bookings by area. The input and object types they use are on GraphQL API reference: Rentals & Bookings types. The add-on apps’ operations are on GraphQL API reference: add-on apps. Keys, versions, limits and errors: API overview.
Send a request #
| Address | POST https://YOUR-API-ADDRESS/graphql/2026-10 (Settings › API shows it) |
| Headers | Authorization: Bearer sirb_your_secret_key and Content-Type: application/json |
| Body | {"query": "…", "variables": {…}, "operationName": "…"} (variables and operationName are optional) |
| Answer | {"data": {…}}, with errors when something couldn’t run |
Queries may also be sent with GET ?query=…&variables=…; mutations only with POST. Send one operation per request. Every operation on this page needs the Rentals & Bookings app; queries need a secret key, and mutations a key with Allow changes (write). The API keys operations work with a key of any of the apps.
curl -s "https://YOUR-API-ADDRESS/graphql/2026-10" \
-H "Authorization: Bearer sirb_your_secret_key" \
-H "Content-Type: application/json" \
-d '{"query": "{ rentalShop { domain currency timezone today } rentalApiCaller { scopes installedApps } }"}'
# 200
{"data": {"rentalShop": {"domain": "your-store.myshopify.com", "currency": "USD", "timezone": "America/New_York", "today": "2026-11-30"},
"rentalApiCaller": {"scopes": ["read", "write"], "installedApps": ["core", "contracts", "deposits"]}}}
The same from JavaScript on your server (Node.js 18 or later, which has fetch):
const RENTALS = 'https://YOUR-API-ADDRESS/graphql/2026-10';
const KEY = process.env.RENTALS_API_KEY; // sirb_…: keep it on the server
async function rentals(query, variables = {}) {
const res = await fetch(RENTALS, {
method: 'POST',
headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
});
if (res.status === 429) throw new Error(`Rate limited, retry in ${res.headers.get('Retry-After')} s`);
const body = await res.json();
if (body.errors?.length) throw Object.assign(new Error(body.errors[0].message), body.errors[0].extensions);
return body.data;
}
// Is a tent free the first weekend of December, and what does it cost?
const pick = { variantId: 'gid://shopify/ProductVariant/44001', startDate: '2026-12-04', endDate: '2026-12-06', quantity: 2 };
const data = await rentals(`
query Check($a: RentalAvailabilityInput!, $p: RentalPriceInput!) {
rentalProductAvailability(input: $a) { isAvailable availableQuantity }
rentalProductPrice(input: $p) { total currency lines { label amount } }
}`, { a: pick, p: pick });
console.log(data.rentalProductAvailability.isAvailable, data.rentalProductPrice.total);
To explore without code, open Settings › API › Open the GraphQL explorer, paste your key in the Headers pane as {"Authorization": "Bearer sirb_your_secret_key"}, and use its Docs pane to browse every type.
How the schema works #
- Ids are global:
gid://sirentals/Booking/42for the app’s objects (Booking, Hold, SerialNumber, Movement, Kit, Balance, CalendarImport, ApiKey …) and Shopify’s own ids for Shopify’s objects (gid://shopify/ProductVariant/44001,gid://shopify/Order/5550001,gid://shopify/Location/66001). EveryIDargument also takes the bare number, and objects carrylegacyResourceId. - Lists that can grow are connections:
first/after(orlast/before),nodesoredges { cursor node },pageInfo { hasNextPage endCursor }andtotalCount. 20 items by default, at most 200. - Mutations take an
inputobject (or a few arguments) and answer the result plususerErrors { code message field data httpStatus }. A refusal (not enough stock, a closed day) is a user error, not an exception.httpStatusis what the REST API would answer. - Dates are in the store’s time zone. Inputs take
2026-12-01,2026-12-01 09:00or2026-12-01T09:00; answers use2026-12-01 09:00:00. - Stays by the night: a product booked by the night takes
checkInandcheckOutforstartDateandendDate. A stay runs from the check-in day to the check-out day ([check-in, check-out)), so it needs at least one night: a same-day or reversed pick is refused withzero_nights. Quotes, availability, calendars and bookings carrynightlyandnights(a booking alsocheckInandcheckOut); a booking keeps the rule it was sold under. - Money is in the store currency: floats for prices and quotes, decimal strings (
"150.00") for balances and amounts that must stay exact. - Enums are upper case (
RESERVED,SEND). - Nested lists (a booking’s serial numbers and moves, an order’s lines) are loaded together for the whole page, so asking for them costs no extra round trips.
Operations #
Each table gives the operation (a query or a mutation, which key may call it, and the type it returns), its arguments and what it does. Most operations take one input object: its fields are listed on the types page.
Store and caller #
| Operation | Arguments | What it does |
|---|---|---|
rentalShopquery · secret or publishable key returns RentalShop! | – | The store the key belongs to: domain, name, currency, time zone, today’s date and whether online booking is ready (checkoutReady). |
rentalApiCallerquery · secret or publishable key returns RentalApiCaller! | – | Who is calling: the kind of credential, a secret key’s scopes and prefix, and the apps the store has installed (installedApps). Handy to test a key. |
Products, availability and prices #
Several of these also work with a storefront’s publishable key: see Headless storefronts.
| Operation | Arguments | What it does |
|---|---|---|
rentalProductsquery · secret key returns [RentalProduct!]! | query: Stringfirst: Int = 25 | Rent variants by title, variant title or SKU (at most 50). An empty query lists the first ones. |
rentalProductAvailabilityquery · secret key returns RentalAvailability! | input: RentalAvailabilityInput! | Can this quantity be rented over these dates? The units free at the busiest moment of the range, counting bookings and live holds, turnaround included. |
rentalProductCalendarquery · secret or publishable key returns RentalCalendar! | input: RentalCalendarInput! | What a date picker needs for one product: fully booked days, the booked intervals (secret keys only) and the full calendar payload the store’s own calendar uses (widgetConfig). |
rentalProductPriceListquery · secret or publishable key returns RentalPriceList! | productId: IDvariantId: ID | The rate card: every period the product is priced by, its price and its price per day. |
rentalProductPricequery · secret or publishable key returns RentalQuote! | input: RentalPriceInput! | The price of a rental over these dates, with the breakdown: exactly what the cart will charge. It prices anything that parses; availability and the store’s rules are checked when you reserve or book. |
rentalProductDayPricesquery · secret or publishable key returns RentalDayPrices! | input: RentalDayPricesInput! | The price of a one-day rental starting on each day of a range (at most 366 days). |
rentalCatalogAvailabilityquery · secret or publishable key returns RentalCatalogAvailability! | productIds: [ID!]handles: [String!]selection: RentalSearchSelectionInput! | For up to 50 products (ids or handles): is each a rental, and is it free for a date search? With a place (where), how far away it is. |
rentalMapMarkersquery · secret or publishable key returns RentalMap! | collection: StringproductIds: [ID!]selection: RentalSearchSelectionInput | Map markers for rental products with a location (at most 250), optionally for a collection, some products or a place; with dates, whether each is free. |
Bookings #
| Operation | Arguments | What it does |
|---|---|---|
rentalBookingsquery · secret key returns RentalBookingConnection! | first: Intafter: Stringlast: Intbefore: Stringfilter: RentalBookingFilterInputsortKey: RentalBookingSortKey = IDreverse: Boolean = true | Bookings, filtered and sorted. Newest first by default. |
rentalBookingquery · secret key returns RentalBooking | id: ID! | One booking, or null when the store has no such booking. |
rentalBookingDatesCheckquery · secret key returns RentalBookingDatesCheck! | id: ID!startDate: String!endDate: String! | Could this booking move to new dates? The rules the new dates break, and the price difference (positive: the customer owes more). |
rentalCustomerBookingsquery · secret key returns RentalCustomerBookings! | customerId: ID! | A customer’s bookings: out now, coming up and past (newest first, at most 500). |
rentalCustomersquery · secret key returns [RentalCustomer!]! | query: String!first: Int = 20 | Customers who have rented before, by name or email (at least 2 letters). |
createRentalBookingmutation · secret key returns RentalBookingCreatePayload! | input: RentalBookingCreateInput! | Book a rental for a customer: the store’s rules apply, the units are held for 7 days and Shopify makes a draft order with a payment link. With block: true, block dates instead (maintenance, private use; no order). |
updateRentalBookingmutation · secret key returns RentalBookingPayload! | id: ID!input: RentalBookingUpdateInput! | Move a booking to new dates (it doesn’t compete with itself; force skips the stock check) or change its notes. Quantity, product and order changes belong to the Shopify order. |
deleteRentalBookingmutation · secret key returns RentalBookingDeletePayload! | id: ID! | Delete blocked dates, or a booking made through the API or an import that has no order. A booking still waiting on its draft order is cancelled and the draft deleted in Shopify. |
deleteRentalBooking refuses bookings that belong to an order (has_order: cancel or refund it in Shopify), imported calendar events (imported), bookings made at checkout, at the counter or in the app (not_deletable), and a draft order that was paid meanwhile (draft_completed).
Orders #
| Operation | Arguments | What it does |
|---|---|---|
rentalOrdersquery · secret key returns RentalOrderConnection! | filter: RentalOrderFilterInputreverse: Boolean = falsefirst: Intafter: Stringlast: Intbefore: String | Orders with a rental running in a window (turnaround included), each with all its rental lines. Sorted by the earliest rental start. Blocked dates and draft-order bookings are not listed. |
rentalOrderquery · secret key returns RentalOrder! | id: ID! | One order’s rentals (an empty list when it has none). |
Send & Return #
The same rules as the Send & Return desk. quantity defaults to the number of serial numbers, else 1. A product that tracks serial numbers needs one serial number per unit at check-out. A batch holds at most 200 items; with atomic: true (the default) one bad item refuses the whole batch with batch_refused and data.failures, and nothing is recorded. With atomic: false, the good items are recorded and the others listed in failures.
| Operation | Arguments | What it does |
|---|---|---|
rentalMoveQueuequery · secret key returns RentalMoveQueueConnection! | direction: RentalMoveDirection!when: String = "all"filter: RentalMoveQueueFilterInputfirst: Intafter: Stringlast: Intbefore: String | The Send & Return desk’s lists: SEND = bookings with units still to go out, by rental start; RETURN = bookings with units out, by rental end. |
rentalMoveQueueCountsquery · secret key returns RentalMoveQueueCounts! | direction: RentalMoveDirection! | How many bookings each list holds: today, overdue, this week and all. |
rentalMovementsquery · secret key returns RentalMovementConnection! | direction: RentalMoveDirection!filter: RentalMovementFilterInputsortKey: RentalMovementSortKey = DATETIMEreverse: Boolean = truefirst: Intafter: Stringlast: Intbefore: String | Every check-out (SEND) or check-in (RETURN) on record, newest first by default. |
sendRentalsmutation · secret key returns RentalMovesPayload! | input: RentalMovesInput! | Check units out: one booking or a batch of up to 200, with serial numbers. A batch is all or nothing unless atomic: false. |
returnRentalsmutation · secret key returns RentalMovesPayload! | input: RentalMovesInput! | Check units in, with the same rules as sendRentals. |
sendRentalByScanmutation · secret key returns RentalScanPayload! | input: RentalScanInput! | Check one unit out from a scanned code: a serial number, an order name (#1042 or 1042), a booking number or a SKU. |
returnRentalByScanmutation · secret key returns RentalScanPayload! | input: RentalScanInput! | Check one unit in from a scanned code (for a serial number: the booking it is out on). |
Serial numbers #
| Operation | Arguments | What it does |
|---|---|---|
rentalSerialNumbersquery · secret key returns RentalSerialNumberConnection! | filter: RentalSerialNumberFilterInputfirst: Intafter: Stringlast: Intbefore: String | Serial numbers, by product, variant, status or part of the code. |
rentalSerialNumberquery · secret key returns RentalSerialNumber | id: ID! | One serial number with its history, or null. |
rentalSerialUsagequery · secret key returns RentalSerialUsage! | input: RentalSerialUsageInput | Use by serial number over a window: days out, idle days, use rate, hires and revenue. Default: the last 30 days. |
rentalSerialLabelsquery · secret key returns RentalSerialLabels! | serialIds: [ID!]productId: IDformat: String = "qr"names: Boolean = false | A printable label sheet (PDF) for some serial numbers, or every one of a product that isn’t retired, as a link that works for 10 minutes. |
rentalSerialTrackingquery · secret key returns RentalSerialTracking! | productId: ID! | Whether a product tracks serial numbers, and how many it has in each status. |
createRentalSerialNumbermutation · secret key returns RentalSerialNumberPayload! | input: RentalSerialNumberCreateInput! | Add one serial number to a rent variant. |
createRentalSerialNumbersmutation · secret key returns RentalSerialNumbersPayload! | input: RentalSerialNumberRangeInput! | Add a run of serial numbers (TENT-001 to TENT-020). Codes that exist already are skipped. |
updateRentalSerialNumbermutation · secret key returns RentalSerialNumberPayload! | id: ID!input: RentalSerialNumberUpdateInput! | Change a serial number; only the fields you send change. Moving it to another variant is refused while it is out. |
deleteRentalSerialNumbermutation · secret key returns RentalSerialNumberDeletePayload! | id: ID! | Delete a serial number. Refused while it is out or once it has history: retire it instead. |
Locations and stock #
| Operation | Arguments | What it does |
|---|---|---|
rentalLocationsquery · secret or publishable key returns [RentalLocation!]! | – | The store’s Shopify locations and whether rentals are picked up there. With two or more that rent, customers choose where they pick up and each product can have its own stock at each location. Storefronts see only the locations that rent, without phone numbers. |
rentalProductStockquery · secret key returns RentalProductStock! | productId: ID! | A product’s rental stock: one shared stock, or units at each location. |
setRentalProductStockmutation · secret key returns RentalProductStockPayload! | input: RentalProductStockInput! | Set a product’s rental stock (a location you leave out gets 0). Per location it also takes a minimum and a maximum to keep and a price rule, and returnRules sets where customers may return the product. Refused with stock_conflict when future bookings would no longer fit, unless force: true. |
rentalStockBoardquery · secret key returns RentalStockBoard! | productId: ID | Units based at each location, free today, out with customers and on the way, per rent variant with stock at each location. |
rentalTransfersquery · secret key returns RentalTransferList! | filter: RentalTransferFilterInputfirst: Int = 50offset: Int = 0 | Transfers, newest first (default: open ones: PLANNED and IN_TRANSIT). |
rentalTransferquery · secret key returns RentalTransfer | id: ID! | One transfer. |
rentalTransferSuggestionsquery · secret key returns [RentalTransferSuggestion!]! | – | Transfers that would bring locations below their minimum back up (from locations above their maximum). Nothing moves by itself. |
createRentalTransfermutation · secret key returns RentalTransferPayload! | input: RentalTransferCreateInput! | Plan a transfer: it counts at once (the origin loses the units from the ship time, the destination gains them at the arrival). Refused with transfer_leaves_short (data.items: each item’s deficit) when the origin would be short for its bookings, unless force: true with a reason. |
dispatchRentalTransfermutation · secret key returns RentalTransferPayload! | input: RentalTransferMoveInput! | Dispatch: the units leave the origin now (they must be free there). Serials scanned out travel with it. |
receiveRentalTransfermutation · secret key returns RentalTransferPayload! | input: RentalTransferMoveInput! | Receive all or part of a dispatched transfer (items, or the serial numbers scanned in); ARRIVED when everything is in. |
cancelRentalTransfermutation · secret key returns RentalTransferPayload! | id: ID! | Cancel: a planned transfer stops counting; a dispatched one is turned back (what is still on the way goes back to the origin). |
setRentalLocationRulesmutation · secret key returns RentalLocationPayload! | locationId: ID!rules: JSON! | Set a location’s own rules: hours, closed days, turnaround, lead time, price rule (see RentalLocation.rules). Keys left out keep their value; null clears one (the store’s setting applies). |
Rental kits #
| Operation | Arguments | What it does |
|---|---|---|
rentalKitsquery · secret key returns RentalKitConnection! | first: Intafter: Stringlast: Intbefore: String | The store’s rental kits, oldest first. |
rentalKitquery · secret or publishable key returns RentalKit | id: ID! | One kit, or null. |
createRentalKitmutation · secret key returns RentalKitPayload! | input: RentalKitCreateInput! | Make a kit: a new Shopify product (active, on no sales channel yet: publish it in Shopify) rented as its items. |
updateRentalKitmutation · secret key returns RentalKitPayload! | id: ID!input: RentalKitUpdateInput! | Change a kit’s title, items, pricing or rules. Existing bookings keep the items they were booked with. |
deleteRentalKitmutation · secret key returns RentalKitDeletePayload! | id: ID! | Remove a kit (refused while a booking of it isn’t over). Its Shopify product is archived. |
Delivery & pickup #
| Operation | Arguments | What it does |
|---|---|---|
rentalHandoverWindowsquery · secret or publishable key returns [RentalHandoverWindow!]! | input: RentalHandoverWindowsInput! | The time slots of a hand-over day for a product and method (pick-up, delivery or transport). |
rentalDeliverySettingsquery · secret key returns JSON! | – | The store’s delivery & pickup settings as JSON (the same object the app’s settings page saves). |
updateRentalDeliverySettingsmutation · secret key returns RentalDeliverySettingsPayload! | settings: JSON! | Change the delivery & pickup settings: what you send is merged over the current settings. |
changeRentalHandovermutation · secret key returns RentalBookingPayload! | input: RentalHandoverChangeInput! | Change a booking’s method, return method, time slots or return tracking. Refused with not_available when the new transit days are booked, unless force. |
rentalDeliveryCheckquery · secret or publishable key returns RentalDeliveryCheck! | postcode: String!productId: IDvariantId: IDlocationId: ID | Can delivery be booked to a postcode, and from which area and location. |
rentalDeliveryZonesquery · secret key returns [RentalDeliveryZone!]! | – | The store’s delivery areas, in order. |
rentalSchedulequery · secret key returns RentalSchedule! | date: StringlocationId: IDmethod: RentalHandoverMethod | One day’s run sheet (default today, store time); locationId narrows to one location, method to one way. |
createRentalDeliveryZonemutation · secret key returns RentalDeliveryZonePayload! | input: RentalDeliveryZoneInput! | Add a delivery area. Once a store has areas, delivery needs a postcode inside one. |
updateRentalDeliveryZonemutation · secret key returns RentalDeliveryZonePayload! | id: ID!input: RentalDeliveryZoneInput! | Change a delivery area (the fields sent change). |
deleteRentalDeliveryZonemutation · secret key returns RentalDeliveryZoneDeletePayload! | id: ID! | Remove a delivery area (bookings keep their postcode). |
Balances (pay part now, rest later) #
paymentUrl (the customer’s payment link) is only given to secret keys. Keep it private.
| Operation | Arguments | What it does |
|---|---|---|
rentalBalancesquery · secret key returns RentalBalanceConnection! | first: Intafter: Stringlast: Intbefore: Stringstatus: RentalBalanceStatusdueBefore: String | Balances of rentals paid in part at checkout. Default: due and overdue, due first. |
rentalBalancequery · secret key returns RentalBalance | id: ID! | One balance, or null. |
sendRentalBalanceInvoicemutation · secret key returns RentalBalancePayload! | input: RentalBalanceInvoiceInput! | Send Shopify’s invoice email with the payment link (not_open once it is paid or waived). |
markRentalBalancePaidmutation · secret key returns RentalBalancePayload! | balanceId: ID! | Record a balance as paid outside the checkout (cash). outstanding_differs when the order owes more than the balance. |
waiveRentalBalancemutation · secret key returns RentalBalancePayload! | balanceId: ID!note: String | Waive a balance: it comes off the order (or its invoice is deleted). |
Subscriptions (rentals billed per period) #
A rental can be billed per period instead of for fixed dates: ongoing until it comes back, or for a set number of periods. The subscription belongs to a booking; the unit stays held until it is returned or the term ends. Start one with reserveRentalDates and a subscription (see the storefront API).
| Operation | Arguments | What it does |
|---|---|---|
rentalSubscriptionsquery · secret key returns RentalSubscriptionConnection! | first: Intafter: Stringlast: Intbefore: Stringstatus: RentalSubscriptionStatuscustomerId: ID | Rentals billed per period: overdue first, then ending, then by next due date. |
rentalSubscriptionquery · secret key returns RentalSubscription | id: ID! | |
endRentalSubscriptionmutation · secret key returns RentalSubscriptionPayload! | input: RentalSubscriptionEndInput! | End the rental: due back by returnBy (default the end of the paid period); billing by invoice stops then. Another app’s subscription must be cancelled in that app too. |
recordRentalSubscriptionPaymentmutation · secret key returns RentalSubscriptionPayload! | input: RentalSubscriptionPaymentInput! | Record a payment for the next unpaid period (cash, bank transfer, a renewal order that wasn’t matched). |
POS alerts #
A rent item rung up at the point of sale without the Rentals desk has no dates and no booking. It raises an alert until the merchant books the dates or dismisses it.
| Operation | Arguments | What it does |
|---|---|---|
rentalPosAlertsquery · secret key returns [RentalPosAlert!]! | status: RentalPosAlertStatusfirst: Int | Rent items sold at POS without the desk, newest first (default: OPEN). |
resolveRentalPosAlertmutation · secret key returns RentalPosAlertPayload! | id: ID!bookingId: IDnote: String | Close a POS alert: with a booking made some other way (bookingId; its order line is attached when it has none), or dismissed with a note. |
Calendar sync (iCal) #
A feed’s url is its only credential: anyone with it can read the feed. Only the host of an imported calendar’s address is shown, because the full address carries the booking channel’s secret.
| Operation | Arguments | What it does |
|---|---|---|
rentalCalendarSyncquery · secret key returns RentalCalendarSync! | productId: ID! | A product’s calendar sync: its feed addresses, its rent variants and the calendars it imports. |
rentalCalendarImportsquery · secret key returns [RentalCalendarImport!]! | productId: ID | The calendars the store imports, for all products or one. |
rotateRentalCalendarFeedmutation · secret key returns RentalCalendarSyncPayload! | productId: ID!flavour: RentalCalendarFeedFlavour = AVAILABILITYvariantId: ID | Give a feed a new address; the old one stops working at once. |
setRentalCalendarBookingsFeedmutation · secret key returns RentalCalendarSyncPayload! | productId: ID!enabled: Boolean!variantId: ID | Turn the bookings feed (every booking with its customer) on or off. |
createRentalCalendarImportmutation · secret key returns RentalCalendarImportPayload! | productId: ID!input: RentalCalendarImportInput! | Import another calendar (Airbnb, Booking.com, Google …): its events block the dates. It is read at once unless syncNow: false. |
updateRentalCalendarImportmutation · secret key returns RentalCalendarImportPayload! | id: ID!input: RentalCalendarImportUpdateInput! | Change an imported calendar; only the fields you send change. |
deleteRentalCalendarImportmutation · secret key returns RentalCalendarImportDeletePayload! | id: ID! | Stop importing a calendar and free the dates it blocked. |
syncRentalCalendarImportmutation · secret key returns RentalCalendarImportPayload! | id: ID! | Read an imported calendar now. |
Rental settings and API keys #
| Operation | Arguments | What it does |
|---|---|---|
rentalSettingsCsvquery · secret key returns String! | – | Every rent variant’s settings as CSV text. Edit it and send it back with importRentalSettings. |
importRentalSettingsmutation · secret key returns RentalSettingsImportPayload! | csv: String!dryRun: Boolean = true | Import rental settings from CSV. dryRun (the default) reports what would change and writes nothing; dryRun: false applies the rows without errors. |
rentalApiKeysquery · secret key returns [RentalApiKey!]! | – | The store’s API keys, active ones first (never a secret). |
createRentalApiKeymutation · secret key returns RentalApiKeyCreatePayload! | input: RentalApiKeyInput! | Make an API key. The secret is in the answer this once only. A key can make keys, but never one with more access than its own. |
revokeRentalApiKeymutation · secret key returns RentalApiKeyPayload! | id: ID! | Revoke an API key at once (revoking twice is harmless). A key may revoke itself. |
Examples #
Today’s check-outs, then send one with its serial numbers #
curl -s "https://YOUR-API-ADDRESS/graphql/2026-10" -H "Authorization: Bearer sirb_your_secret_key" -H "Content-Type: application/json" \
-d '{"query": "{ rentalMoveQueueCounts(direction: SEND) { today overdue } rentalMoveQueue(direction: SEND, when: \"today\", first: 50) { edges { due quantity serials node { id orderName productName } } } }"}'
mutation Send($items: [RentalMoveItemInput!]!) {
sendRentals(input: {items: $items, atomic: true}) {
processed
items { booking { id quantitySent status } serials outstanding }
failures { index bookingId code message }
userErrors { code message data }
}
}
# variables: {"items": [{"bookingId": "gid://sirentals/Booking/42", "serials": ["TENT-001", "TENT-003"]}]}
A refused batch answers userErrors: [{code: "batch_refused", data: {failures: [{index, booking_id, code, message, status}]}}] and records nothing.
Block dates for maintenance, then free them #
mutation Block {
createRentalBooking(input: {variantId: "44001", startDate: "2026-12-01", endDate: "2026-12-03", quantity: 1, block: true, notes: "Annual service"}) {
booking { id legacyResourceId startDate endDate status source }
userErrors { code message data }
}
}
# then, with the id it answered:
mutation Free {
deleteRentalBooking(id: "gid://sirentals/Booking/43") { deletedBookingId userErrors { code message } }
}
A booking with its serial numbers, moves and order #
query Booking {
rentalBooking(id: "42") {
id orderName status state startDate endDate quantity quantitySent quantityReturned
customer { name email }
serials { code out }
movements { direction datetime quantity serials }
location { name }
}
}
Orders with a rental next week #
query NextWeek {
rentalOrders(filter: {startDate: "2026-12-07", endDate: "2026-12-13"}, first: 50) {
totalCount
nodes { name status earliestStart customer { name } bookings { productName quantity startDate endDate status } }
}
}
Rotate your own key #
mutation Rotate {
createRentalApiKey(input: {name: "Warehouse scanner 2026", scopes: ["read", "write"]}) {
apiKey { id prefix scopes }
secret # shown this once: store it, deploy it
userErrors { code message }
}
}
# once the new key is in use:
# mutation { revokeRentalApiKey(id: "gid://sirentals/ApiKey/3") { apiKey { revokedAt } userErrors { code } } }
Quote a stay by the night #
query Stay {
rentalProductPrice(input: {variantId: "44001", checkIn: "2026-12-04", checkOut: "2026-12-07", quantity: 1}) {
nightly nights lengthUnit total currency
lines { label kind amount }
}
rentalProductCalendar(input: {variantId: "44001", startDate: "2026-12-01", endDate: "2026-12-31"}) {
nightly turnoverDates
stayDays { date state checkIn checkOut }
}
}
Move stock between locations #
query Board {
rentalStockBoard {
locations { id publicName }
rows { title total locations { locationId units free out inTransit belowMin } }
}
rentalTransferSuggestions { title fromLocationId toLocationId quantity reason }
}
mutation Plan {
createRentalTransfer(input: {fromLocationId: "66001", toLocationId: "66002", shipAt: "2026-12-02", arriveAt: "2026-12-03", items: [{variantId: "44001", quantity: 4}]}) {
transfer { id status items { variantId quantity } }
userErrors { code message data } # transfer_leaves_short: the origin would be short; force: true with a reason
}
}
# then: dispatchRentalTransfer(input: {id: "gid://sirentals/StockTransfer/9"}), receiveRentalTransfer(input: {id: "…"}) at the other end
Can we deliver to this postcode, and what is on the run sheet #
query Delivery {
rentalDeliveryCheck(postcode: "SW1A 1AA", variantId: "44001") {
ok postcode locationId code message earliestStart
zone { id name }
}
rentalSchedule(date: "2026-12-04") {
day deliveries { orderName customerName addressText window items { title quantity } }
collections { orderName addressText window }
pickups { orderName } returns { orderName } toPost { orderName } dueBack { orderName late }
route mapLinks
}
}
End a subscription and record a payment #
query Live {
rentalSubscriptions(first: 20, status: PAST_DUE) {
nodes { id orderName status interval periodPrice currency paidThrough nextDue returnBy }
}
}
mutation Stop {
endRentalSubscription(input: {subscriptionId: "gid://sirentals/Subscription/5", returnBy: "2026-12-31", note: "Customer asked"}) {
subscription { status returnBy }
userErrors { code message }
}
}
mutation Paid {
recordRentalSubscriptionPayment(input: {subscriptionId: "gid://sirentals/Subscription/6", amount: "45.00", note: "Bank transfer"}) {
subscription { status paidThrough nextDue }
userErrors { code message }
}
}
