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. - 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. 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). Refused with stock_conflict when future bookings would no longer fit, unless force: true. |
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 posted). |
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. |
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). |
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 } } }
