Skip to content

App proxy endpoints

Rentshelf uses Shopify’s App Proxy to expose dynamic data to the storefront. All endpoints are served from your shop domain:

https://<your-shop>.myshopify.com/apps/rental/<endpoint>

Shopify proxies these to the app at /proxy/<endpoint> with a signed HMAC.

Returns rental configuration for a single product.

Query params

ParamDescription
product_idShopify product GID (or numeric ID).
handleProduct handle (alternate lookup).
startOptional ISO date, for availability lookups.
endOptional ISO date.

200 response (product is configured as a rental):

{
"productId": "gid://shopify/Product/123",
"pricePerDay": 10,
"pricingMode": "DAILY",
"minDays": 1,
"maxDays": 30,
"currency": "USD",
"addons": [
{ "id": "...", "name": "Insurance", "price": 5, "priceType": "PER_DAY", "isRequired": false, "maxQuantity": 1 }
],
"tiers": [
{ "days": 7, "price": 60, "label": null }
],
"blockedDates": ["2026-10-14", "2026-10-15"],
"widget": { "heading": "Rent this product", "...": "..." }
}

404 response — the product isn’t configured as a rental (or is paused). The storefront picker uses this to remove itself from the DOM on non-rental products.

Returns an authoritative server-side quote for a date range, including availability check and add-ons.

Query params

ParamDescription
product_idShopify product GID.
startISO start date.
endISO end date.
addonsJSON-encoded add-on selections.
unitsNumber of units to rent (default 1).

200 response:

{
"available": true,
"days": 4,
"subtotal": 40,
"addonsTotal": 20,
"total": 60,
"deposit": 12,
"currency": "USD"
}

This endpoint is used for defensive confirmation before adding to cart. The current storefront picker does client-side quoting with the same logic as calculateQuote, but you can opt to call this for a final server-blessed number (useful for custom integrations).

Creates or updates a CHECKOUT / PENDING booking as a soft hold on dates.

Body (JSON):

{
"productId": "gid://shopify/Product/123",
"start": "2026-10-14",
"end": "2026-10-17",
"days": 3,
"subtotal": 30,
"total": 50,
"deposit": 10,
"addons": [{ "id": "...", "name": "Insurance", "qty": 1, "price": 5 }],
"currency": "USD",
"cartToken": "z1abc..."
}

200 response:

{
"bookingId": "cln..."
}

The hold prevents two customers from checking out the same unit on overlapping dates. Holds expire after 60 minutes if no order is placed. On successful order placement, the orders/create webhook upgrades the hold to a real Booking.

All proxy calls include an HMAC signature added by Shopify. The Remix handlers at /proxy/*.tsx verify the signature via authenticate.public.appProxy() before responding. Direct calls to the app’s URL (bypassing the shop domain) will fail authentication.

The app uses Shopify’s standard Admin API rate limit bucket. App proxy calls themselves aren’t rate-limited by Shopify, but the underlying work (database reads, product sync) may be throttled if the shop is high-traffic. Contact support if you see sustained 429s.