{"openapi":"3.1.0","info":{"title":"Rentshelf API","version":"1.0.0","summary":"Read rental bookings, products, availability and locations; receive signed booking webhooks.","description":"Available on every plan with the API access add-on ($19/month, billed through Shopify). Authenticate with a per-shop API key created in Rentshelf > Settings > API access. All responses are JSON; errors use `{ \"error\": { \"code\", \"message\", \"param\" } }` where `param` is the JSON path of the offending field when known. Rate limit: 60 requests per minute per key, reads and writes combined.\n\n**Writes act on live data. There is no test mode or sandbox: creating or changing bookings can email customers and send Shopify payment requests.** POST and PATCH accept an `Idempotency-Key` header (kept 24 hours).\n\n**No-code integrations:** Zapier and Make subscribe to events with `POST /webhook_endpoints` (REST hooks) and unsubscribe with `DELETE /webhook_endpoints/{id}`; each delivery body is the event envelope, and the booking is in `data.object`. Shopify Flow triggers (Rental booked, Rental status changed, Rental picked up, Rental returned, Rental overdue) are sent by Rentshelf directly and need no API key.","contact":{"name":"Rentshelf support","url":"https://rentshelf.app/contact"}},"servers":[{"url":"https://rentshelf.app/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account"},{"name":"Quotes"},{"name":"Bookings"},{"name":"Products"},{"name":"Availability"},{"name":"Blackouts"},{"name":"Locations"},{"name":"Webhook endpoints"}],"paths":{"/me":{"get":{"tags":["Account"],"operationId":"getMe","summary":"Shop and API key details","description":"Works with any valid key regardless of scopes.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}}},"/bookings":{"get":{"tags":["Bookings"],"operationId":"listBookings","summary":"List bookings","description":"Requires `bookings:read`. Newest first by `created_at`; when `updated_since` is set, ordered by `updated_at` ascending for incremental sync. Unpaid checkout holds are never returned.","parameters":[{"name":"status","in":"query","required":false,"description":"Comma-separated: pending, confirmed, active, returned, cancelled.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Only bookings whose rental window ends on or after this date.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Only bookings whose rental window starts on or before this date.","schema":{"type":"string","format":"date"}},{"name":"product_id","in":"query","required":false,"description":"Rentshelf product ID (see /products).","schema":{"type":"string"}},{"name":"email","in":"query","required":false,"description":"Only bookings for this customer email (exact match, as stored or lower-cased).","schema":{"type":"string","format":"email"}},{"name":"updated_since","in":"query","required":false,"description":"ISO 8601 timestamp; bookings updated at or after it.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1-100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page."}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}},"post":{"tags":["Bookings"],"operationId":"createBooking","summary":"Create a booking","description":"Requires `bookings:write`. **Live data — there is no test mode.** Priced and checked exactly like a quote, then saved like an admin manual booking (source `manual`). With `status: confirmed` the customer receives the shop's confirmation email when the shop has it enabled (opt out with `send_confirmation_email: false`). `send_payment_request: true` creates a Shopify payment link for the amount due and emails it to the customer; the link is returned in `payment_request.url`. The booking is kept even if the payment request fails (see `payment_request.error`).","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingCreate"},"example":{"product_id":"PRODUCT_ID","start_date":"2026-12-04","end_date":"2026-12-06","quantity":1,"add_ons":[{"id":"ADDON_ID","quantity":1}],"customer":{"name":"Ada Lovelace","email":"ada@example.com","phone":"+447700900123"},"notes":"Leave at reception","status":"confirmed","send_payment_request":true}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWrite"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/bookings/{id}":{"get":{"tags":["Bookings"],"operationId":"getBooking","summary":"Retrieve a booking","description":"Requires `bookings:read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"patch":{"tags":["Bookings"],"operationId":"updateBooking","summary":"Change a booking","description":"Requires `bookings:write`. **Live data — there is no test mode.** Dates, quantity, variant, add-ons, delivery method and times go through the admin booking-change flow: the price is recalculated, stock is re-checked, the change is recorded in the booking history and any price difference is tracked as a balance (no money moves). `notify_customer: true` emails the customer about the change. Manual bookings edited with custom pricing and timed appointments cannot be changed here. Status transitions: pending → confirmed/cancelled; confirmed → active/returned/cancelled; active → returned/cancelled. Status changes emit the matching webhook events.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingUpdate"},"example":{"end_date":"2026-12-07","reason":"Customer extended by one day","notify_customer":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWrite"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/bookings/{id}/cancel":{"post":{"tags":["Bookings"],"operationId":"cancelBooking","summary":"Cancel a booking","description":"Requires `bookings:write`. Same as PATCH with `{ \"status\": \"cancelled\" }`; cancelling an already cancelled booking returns it unchanged. Shopify orders are not refunded or cancelled.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWrite"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/quotes":{"post":{"tags":["Quotes"],"operationId":"createQuote","summary":"Price and availability for a rental","description":"Requires `availability:read` or `bookings:write`. Nothing is saved. Uses the storefront pricing engine: duration packages, tiers, weekend and seasonal pricing (when the plan includes them), add-on limits per duration, minimum notice, booking window, schedule and min/max duration. Availability uses the same stock calculation as checkout (bookings, buffers, blackouts, locations).","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"example":{"product_id":"PRODUCT_ID","start_date":"2026-12-04","end_date":"2026-12-06","quantity":2,"add_ons":[{"id":"ADDON_ID","quantity":1}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/products/{id}":{"get":{"tags":["Products"],"operationId":"getProduct","summary":"Retrieve a rental product","description":"Requires `products:read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"patch":{"tags":["Products"],"operationId":"updateProduct","summary":"Update rental settings","description":"Requires `products:write`. Only Rentshelf rental settings change; Shopify product data (title, price, inventory, status) is never touched. `total_units` applies to products with shared stock (not per-variant stock or bundles). Activating a product respects the plan's active product limit.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"},"example":{"total_units":6,"max_days":14}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/products":{"get":{"tags":["Products"],"operationId":"listProducts","summary":"List rental products","description":"Requires `products:read`. Includes pricing, duration options, add-ons and deposit settings.","parameters":[{"name":"active","in":"query","required":false,"description":"Filter by active state.","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1-100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page."}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}}},"/availability":{"get":{"tags":["Availability"],"operationId":"getAvailability","summary":"Available units per day","description":"Requires `availability:read`. Uses the same stock calculation as storefront checkout (bookings, buffers, blackouts, schedule). At most 93 days per request; both dates inclusive.","parameters":[{"name":"product_id","in":"query","required":true,"description":"Rentshelf product ID.","schema":{"type":"string"}},{"name":"from","in":"query","required":true,"description":"First date.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":true,"description":"Last date (inclusive).","schema":{"type":"string","format":"date"}},{"name":"variant_id","in":"query","required":false,"description":"Shopify variant ID or GID, for per-variant stock.","schema":{"type":"string"}},{"name":"location_id","in":"query","required":false,"description":"Rentshelf location ID, for location stock.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Availability"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}}},"/blackouts":{"get":{"tags":["Blackouts"],"operationId":"listBlackouts","summary":"List blackout periods","description":"Requires `availability:read`. Store-wide and product blackouts overlapping [from, to]; at most 366 days.","parameters":[{"name":"from","in":"query","required":true,"description":"First date.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":true,"description":"Last date (inclusive).","schema":{"type":"string","format":"date"}},{"name":"product_id","in":"query","required":false,"description":"Only store-wide blackouts and this product's blackouts.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Blackout"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page."}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}},"post":{"tags":["Blackouts"],"operationId":"createBlackout","summary":"Block dates","description":"Requires `availability:write`. Blocks `units_blocked` units per day (0 = calendar note only) for the whole store or one product, both dates inclusive, at most 366 days. Like the admin calendar, existing blackout days of the same scope inside the range are replaced. Existing bookings are not changed.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlackoutCreate"},"example":{"product_id":"PRODUCT_ID","start_date":"2026-12-24","end_date":"2026-12-26","reason":"Holiday","units_blocked":99}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blackout"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/blackouts/{id}":{"delete":{"tags":["Blackouts"],"operationId":"deleteBlackout","summary":"Remove a blackout","description":"Requires `availability:write`. Removes every day of the series.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}}},"/webhook_endpoints":{"get":{"tags":["Webhook endpoints"],"operationId":"listWebhookEndpoints","summary":"List webhook endpoints","description":"Requires `webhooks:write`. Secrets are never listed.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page."}}}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}},"post":{"tags":["Webhook endpoints"],"operationId":"createWebhookEndpoint","summary":"Subscribe a URL to booking events","description":"Requires `webhooks:write`. REST-hook subscribe for Zapier, Make and similar tools. The URL must be public `https://` (no private addresses, no redirects). `events` defaults to every booking event. The signing `secret` is returned only in this response. At most 10 endpoints per shop.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreate"},"example":{"url":"https://hooks.zapier.com/hooks/standard/123/abc/","events":["booking.created","booking.cancelled"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/webhook_endpoints/{id}":{"delete":{"tags":["Webhook endpoints"],"operationId":"deleteWebhookEndpoint","summary":"Unsubscribe","description":"Requires `webhooks:write`. Deletes the endpoint and its delivery history.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}}},"/locations":{"get":{"tags":["Locations"],"operationId":"listLocations","summary":"List pickup locations","description":"Requires `locations:read`.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Location"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page."}}}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}}}},"webhooks":{"booking.created":{"post":{"summary":"Sent when a booking is created","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"booking.created"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}},"booking.updated":{"post":{"summary":"Sent when a booking is updated","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"booking.updated"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}},"booking.cancelled":{"post":{"summary":"Sent when a booking is cancelled","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"booking.cancelled"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}},"booking.picked_up":{"post":{"summary":"Sent when a booking is picked up","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"booking.picked_up"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}},"booking.returned":{"post":{"summary":"Sent when a booking is returned","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"booking.returned"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}},"ping":{"post":{"summary":"Test event sent from the admin","parameters":[{"name":"Rentshelf-Signature","in":"header","required":true,"schema":{"type":"string"},"description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"t.body\" with the endpoint secret>`"},{"name":"Rentshelf-Event","in":"header","required":true,"schema":{"const":"ping"}},{"name":"Rentshelf-Delivery","in":"header","required":true,"schema":{"type":"string"},"description":"Unique per delivery attempt sequence; the event `id` is stable across endpoints."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return any 2xx within 10 seconds. Anything else is retried up to 6 attempts with exponential backoff."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"rs_live_...","description":"Scopes: bookings:read, products:read, availability:read, locations:read, bookings:write, products:write, availability:write, webhooks:write. A write scope also grants the matching read scope."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Recommended for every POST and PATCH (a UUID). For 24 hours, retrying with the same key and the same JSON body replays the original successful response (with `Idempotent-Replayed: true`) instead of acting twice. The same key with a different body or endpoint returns 422 `idempotency_conflict`; a retry while the first request is still running returns 409 `idempotency_in_progress`. Failed requests are not stored, so they can be retried with the same key."}},"responses":{"E400":{"description":"Invalid request: malformed JSON, unknown field, bad query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"Missing, malformed or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403":{"description":"API access disabled, missing scope, or plan limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409":{"description":"Conflict: not enough stock, invalid status transition, concurrent change, or idempotent request in progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E413":{"description":"Request body over 64 KB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E415":{"description":"Body is not application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E422":{"description":"Validation error (see `param`) or idempotency_conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"Rate limited; see Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"enum":["unauthorized","forbidden","api_access_disabled","insufficient_scope","not_found","invalid_request","rate_limited","method_not_allowed","internal_error","validation_error","conflict","unavailable","plan_limit","payload_too_large","unsupported_media_type","idempotency_conflict","idempotency_in_progress"]},"message":{"type":"string"},"param":{"type":"string","description":"JSON path of the offending field, e.g. `customer.email` or `add_ons[0].quantity`."}}}}},"QuoteRequest":{"type":"object","additionalProperties":false,"required":["product_id","start_date","end_date"],"properties":{"product_id":{"type":"string"},"variant_id":{"type":"string","description":"Shopify variant ID or GID (per-variant pricing or stock)."},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date","description":"Return date. For fixed-duration products it must match the chosen `duration`."},"selected_dates":{"type":"array","items":{"type":"string","format":"date"},"description":"Multiple-date products only."},"duration":{"type":"object","additionalProperties":false,"required":["value"],"properties":{"value":{"type":"integer"},"unit":{"enum":["day","hour"]}},"description":"Required for fixed-duration products: one of the product's `duration.options`."},"quantity":{"type":"integer","minimum":1,"maximum":1000,"default":1},"add_ons":{"type":"array","maxItems":50,"items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","description":"Add-on ID from GET /products."},"quantity":{"type":"integer","minimum":0,"maximum":1000,"default":1}}}},"location_id":{"type":"string"},"delivery_method":{"type":"string","description":"One of the product's configured delivery method names."},"pickup_time":{"type":"string"},"return_time":{"type":"string"}}},"Quote":{"type":"object","properties":{"object":{"const":"quote"},"product_id":{"type":"string"},"variant_id":{"type":["string","null"]},"location_id":{"type":["string","null"]},"delivery_method":{"type":["string","null"]},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"selected_dates":{"type":"array","items":{"type":"string","format":"date"}},"duration":{"type":["object","null"],"properties":{"value":{"type":"number"},"unit":{"enum":["day","hour"]},"label":{"type":"string"}}},"days":{"type":"integer"},"quantity":{"type":"integer"},"currency":{"type":"string"},"add_ons":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"price_type":{"type":"string"},"price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"quantity":{"type":"integer"}}}},"price_per_day":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"rental_total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"add_ons_total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"deposit":{"type":"object","properties":{"type":{"enum":["booking","security"]},"amount":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]}}},"due_today":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"remaining_balance":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"balance_due_date":{"type":["string","null"],"format":"date"},"breakdown":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"amount":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]}}}},"available":{"type":"boolean"},"available_units":{"type":["integer","null"]},"unavailable_dates":{"type":"array","items":{"type":"string","format":"date"}}}},"BookingCreate":{"type":"object","additionalProperties":false,"required":["product_id","start_date","end_date","customer"],"properties":{"product_id":{"type":"string"},"variant_id":{"type":"string","description":"Shopify variant ID or GID (per-variant pricing or stock)."},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date","description":"Return date. For fixed-duration products it must match the chosen `duration`."},"selected_dates":{"type":"array","items":{"type":"string","format":"date"},"description":"Multiple-date products only."},"duration":{"type":"object","additionalProperties":false,"required":["value"],"properties":{"value":{"type":"integer"},"unit":{"enum":["day","hour"]}},"description":"Required for fixed-duration products: one of the product's `duration.options`."},"quantity":{"type":"integer","minimum":1,"maximum":1000,"default":1},"add_ons":{"type":"array","maxItems":50,"items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","description":"Add-on ID from GET /products."},"quantity":{"type":"integer","minimum":0,"maximum":1000,"default":1}}}},"location_id":{"type":"string"},"delivery_method":{"type":"string","description":"One of the product's configured delivery method names."},"pickup_time":{"type":"string"},"return_time":{"type":"string"},"customer":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","maxLength":200},"email":{"type":"string","format":"email"},"phone":{"type":"string","description":"E.164 recommended."}}},"notes":{"type":"string","maxLength":2000},"status":{"enum":["pending","confirmed"],"default":"confirmed"},"send_confirmation_email":{"type":"boolean","default":true,"description":"Only for `confirmed`, and only when the shop's confirmation email setting is on."},"send_payment_request":{"type":"boolean","default":false,"description":"Create and email a Shopify payment link for the amount due. Requires `customer.email`."}}},"BookingUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"selected_dates":{"type":"array","items":{"type":"string","format":"date"}},"duration":{"type":"object","additionalProperties":false,"required":["value"],"properties":{"value":{"type":"integer"},"unit":{"enum":["day","hour"]}},"description":"Required for fixed-duration products: one of the product's `duration.options`."},"quantity":{"type":"integer","minimum":1,"maximum":1000},"variant_id":{"type":["string","null"]},"add_ons":{"type":"array","maxItems":50,"items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","description":"Add-on ID from GET /products."},"quantity":{"type":"integer","minimum":0,"maximum":1000,"default":1}}},"description":"Replaces the full add-on selection."},"delivery_method":{"type":["string","null"]},"pickup_time":{"type":["string","null"],"pattern":"^\\d{2}:\\d{2}$"},"return_time":{"type":["string","null"],"pattern":"^\\d{2}:\\d{2}$"},"notes":{"type":["string","null"],"maxLength":2000},"status":{"enum":["pending","confirmed","active","returned","cancelled"]},"return_condition":{"enum":["good","minor_damage","damaged","lost"],"description":"With `status: returned` only."},"reason":{"type":"string","maxLength":500,"description":"Saved in the booking change history."},"notify_customer":{"type":"boolean","default":false,"description":"Email the customer about date/item changes."}}},"BookingWrite":{"allOf":[{"$ref":"#/components/schemas/Booking"},{"type":"object","properties":{"changed":{"type":"boolean","description":"PATCH/cancel: whether anything changed."},"confirmation_email":{"enum":["sent","skipped","failed"],"description":"POST only."},"customer_notification":{"enum":["sent","failed"]},"payment_request":{"type":["object","null"],"properties":{"id":{"type":["string","null"]},"status":{"type":"string","description":"open, failed, not_needed, ..."},"amount":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"currency":{"type":"string"},"url":{"type":["string","null"],"format":"uri"},"email_sent":{"type":"boolean"},"error":{"type":["string","null"]}}}}}]},"ProductUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"active":{"type":"boolean"},"total_units":{"type":"integer","minimum":0,"maximum":100000},"min_units":{"type":"integer","minimum":1,"maximum":1000},"max_units":{"type":["integer","null"],"minimum":1,"maximum":1000},"min_days":{"type":"integer","minimum":1,"maximum":3650},"max_days":{"type":"integer","minimum":1,"maximum":3650}}},"BlackoutCreate":{"type":"object","additionalProperties":false,"required":["start_date","end_date"],"properties":{"product_id":{"type":"string","description":"Omit for a store-wide blackout."},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date","description":"Inclusive."},"reason":{"type":"string","maxLength":200},"units_blocked":{"type":"integer","minimum":0,"default":1}}},"Blackout":{"type":"object","properties":{"object":{"const":"blackout"},"id":{"type":"string"},"scope":{"enum":["store","product"]},"product_id":{"type":["string","null"]},"product_title":{"type":["string","null"]},"reason":{"type":"string"},"units_blocked":{"type":"integer"},"note_only":{"type":"boolean"},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"dates":{"type":"array","items":{"type":"string","format":"date"}}}},"WebhookEndpointCreate":{"type":"object","additionalProperties":false,"required":["url"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"enum":["booking.created","booking.updated","booking.cancelled","booking.picked_up","booking.returned"]}},"description":{"type":"string","maxLength":120}}},"WebhookEndpoint":{"type":"object","properties":{"object":{"const":"webhook_endpoint"},"id":{"type":"string"},"url":{"type":"string"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"enum":["booking.created","booking.updated","booking.cancelled","booking.picked_up","booking.returned"]}},"active":{"type":"boolean"},"disabled_reason":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"WebhookEndpointCreated":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpoint"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string","description":"whsec_... signing secret. Shown only once."}}}]},"Deleted":{"type":"object","properties":{"object":{"type":"string"},"id":{"type":"string"},"deleted":{"const":true}}},"Me":{"type":"object","properties":{"object":{"const":"api_key_context"},"shop":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":["string","null"]},"currency":{"type":"string"},"timezone":{"type":"string"}}},"api_key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"enum":["bookings:read","products:read","availability:read","locations:read","bookings:write","products:write","availability:write","webhooks:write"]}},"created_at":{"type":"string","format":"date-time"}}},"rate_limit":{"type":"object","properties":{"limit_per_minute":{"type":"integer"}}}}},"Booking":{"type":"object","properties":{"object":{"const":"booking"},"id":{"type":"string"},"status":{"enum":["pending","confirmed","active","returned","cancelled"]},"source":{"type":"string","description":"storefront, manual, import, checkout"},"product":{"type":"object","properties":{"id":{"type":"string"},"shopify_product_id":{"type":["string","null"]},"title":{"type":["string","null"]}}},"variant":{"type":["object","null"],"properties":{"shopify_variant_id":{"type":"string"},"title":{"type":["string","null"]}}},"order":{"type":["object","null"],"properties":{"shopify_order_id":{"type":"string"},"name":{"type":["string","null"]}}},"customer":{"type":"object","properties":{"shopify_customer_id":{"type":["string","null"]},"name":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"note":{"type":["string","null"]},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"selected_dates":{"type":"array","items":{"type":"string","format":"date"}},"start_at":{"type":["string","null"],"format":"date-time"},"end_at":{"type":["string","null"],"format":"date-time"},"time_zone":{"type":["string","null"]},"pickup_time":{"type":["string","null"]},"return_time":{"type":["string","null"]},"days":{"type":"integer"},"quantity":{"type":"integer"},"location_id":{"type":["string","null"]},"delivery_method":{"type":["string","null"]},"add_ons":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"quantity":{"type":"integer"}}}},"currency":{"type":"string"},"subtotal":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"add_ons_total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"shipping_total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"order_total":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"deposit":{"type":"object","properties":{"type":{"type":["string","null"]},"amount":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]}}},"due_today":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"remaining_balance":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"balance_due_date":{"type":["string","null"],"format":"date"},"returned_at":{"type":["string","null"],"format":"date-time"},"return_condition":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Product":{"type":"object","properties":{"object":{"const":"product"},"id":{"type":"string"},"shopify_product_id":{"type":"string"},"handle":{"type":["string","null"]},"title":{"type":["string","null"]},"active":{"type":"boolean"},"currency":{"type":"string"},"pricing":{"type":"object","properties":{"mode":{"type":"string"},"price_per_day":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"fixed_price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"tiers":{"type":"array","items":{"type":"object","properties":{"days":{"type":"integer"},"price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"label":{"type":["string","null"]}}}}}},"booking_type":{"type":"string"},"duration":{"type":"object","properties":{"mode":{"type":"string"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"number"},"unit":{"enum":["day","hour"]},"label":{"type":"string"},"price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]}}}},"min_days":{"type":"integer"},"max_days":{"type":"integer"},"buffer_days_before":{"type":"integer"},"buffer_days_after":{"type":"integer"}}},"timed_slots":{"type":"boolean"},"bundle":{"type":"boolean"},"inventory":{"type":"object","properties":{"stock_mode":{"type":"string"},"total_units":{"type":"integer"},"min_units":{"type":"integer"},"max_units":{"type":["integer","null"]},"variants":{"type":"array","items":{"type":"object","properties":{"shopify_variant_id":{"type":["string","null"]},"title":{"type":["string","null"]},"units":{"type":"integer"}}}}}},"deposit":{"type":"object","properties":{"type":{"type":"string"},"inherits_shop_default":{"type":"boolean"},"percent":{"type":["integer","null"]},"fixed_amount":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]}}},"add_ons":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"price_type":{"type":"string"},"price":{"type":["string","null"],"description":"Decimal amount with two fractional digits, in `currency`.","examples":["120.00"]},"required":{"type":"boolean"},"max_quantity":{"type":"integer"}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Availability":{"type":"object","properties":{"object":{"const":"availability"},"product_id":{"type":"string"},"variant_id":{"type":["string","null"]},"location_id":{"type":["string","null"]},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"timed_slots":{"type":"boolean","description":"Timed-slot products report day capacity excluding timed bookings."},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"available_units":{"type":"integer"},"total_units":{"type":"integer"},"bookable":{"type":"boolean"}}}}}},"Location":{"type":"object","properties":{"object":{"const":"location"},"id":{"type":"string"},"name":{"type":"string"},"address":{"type":["string","null"]},"shopify_location_id":{"type":["string","null"]},"active":{"type":"boolean"},"position":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}},"Event":{"type":"object","properties":{"id":{"type":"string","description":"Stable event ID (evt_...). Use it to deduplicate."},"object":{"const":"event"},"type":{"enum":["booking.created","booking.updated","booking.cancelled","booking.picked_up","booking.returned","ping"]},"api_version":{"const":"v1"},"created_at":{"type":"string","format":"date-time"},"shop":{"type":"string"},"data":{"type":"object","properties":{"object":{"$ref":"#/components/schemas/Booking"},"previous_status":{"type":["string","null"]}}}}}}}}