The REST API v1 endpoints of SI Refundable Deposits: read an order’s deposits, refund them to the original payment method, and manage product deposit rules. The key, limits, pagination and error format are the same as for all our apps: see the API overview. The same operations are in GraphQL: GraphQL API reference: Refundable Security Deposits.
Needs the Refundable Security Deposits app. It works on a store without Rentals & Bookings. Make the key in the app under Settings › API access; a key made in any of our apps works too, because keys belong to the store. On a store without the app, every endpoint here answers 403 with the code rentals_rest_app_not_installed and data.app: "deposits".
Deposits charged with rentals, refunds to the original payment method, and product deposit rules. See Refunding deposits. Amounts are decimal strings in the order’s currency.
The examples use two shell variables, API="https://YOUR-API-ADDRESS/api/v1" and KEY="sirb_your_secret_key". GET needs a read key; everything else needs a key with Allow changes (write).
Deposits, refunds and product rules #
An order’s deposits answer:
{
"order_id": 5550001, "order_name": "#1042", "currency": "USD",
"deposits": [{"id": 17, "order_id": 5550001, "order_name": "#1042", "line_item_id": 13002,
"title": "Party tent 6×12 m · Dec 4, 2026 – Dec 6, 2026", "quantity": 1,
"amount": "200.00", "tax": "0.00", "total": "200.00", "refunded": "0.00", "remaining": "200.00",
"currency": "USD", "status": "not_refunded", "status_label": "Held", "auto_refund": true,
"returned_at": null, "release_after": null, "refunded_at": null, "auto_error": null, "log": []}],
"totals": {"total": "200.00", "refunded": "0.00", "remaining": "200.00"},
"status": "not_refunded", "status_label": "Held", "can_refund": true,
"auto_refund": {"store": true, "override": null, "effective": true, "days": 0, "release_after": null, "returned": false}
}
status is not_refunded, partially_refunded or fully_refunded (null when the order has no deposits). auto_refund says whether the rest is refunded automatically after the return: the store setting, this order’s override and the effective result. Each deposit’s log lists its refunds: [{at, amount, kept, reason, automatic}].
GET /api/v1/deposits/orders/{orderId} #
An order’s deposits. The order is read from Shopify the first time; refresh=true reads it again. 404 order_not_found.
curl -s "$API/deposits/orders/5550001" -H "Authorization: Bearer $KEY"
POST /api/v1/deposits/orders/{orderId}/refund #
Refunds deposits to the original payment method. The app sends Shopify an idempotency key built from the order, the deposits and what they had refunded before, so a retried request can’t refund twice.
| Body field | Notes |
|---|---|
deposit_ids (or deposit_id) | The deposits to refund; none means every deposit of the order. |
amount | Refund this much of one deposit ("150.00"). |
keep | Or keep this much of one deposit (damage, late fees) and refund the rest. |
reason | Shown on the refund in Shopify (up to 400 characters). |
curl -s -X POST "$API/deposits/orders/5550001/refund" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"deposit_ids": [17], "keep": "50.00", "reason": "Scratched frame"}'
# 200
{"refund": {"refund_id": "gid://shopify/Refund/9900001", "amount": "150.00", "deposits": [17]},
"order_id": 5550001, "status": "fully_refunded", "totals": {"total": "200.00", "refunded": "150.00", "remaining": "0.00"}, "…": "…"}
Refusals: 404 order_not_found, 404 deposit_not_found, 400 one_deposit (amount or keep with several deposits), 400 bad_amount, 400 bad_keep, 400 nothing_to_refund, 400 no_payment (nothing was paid to refund to), 400 refund_failed (Shopify refused; the attempt is recorded), 502 shopify_error.
PUT /api/v1/deposits/orders/{orderId}/auto-refund #
Turns the automatic refund on or off for this order. Body: {"enabled": true}, false, or null to follow the store setting. Answers the order’s deposits.
GET /api/v1/deposits/products #
The products with their own deposit rule: [{product_id, title, rule: {mode, amount, per}}]. The others use the store default.
GET /api/v1/deposits/products/{productId} #
A product’s rule, its own or the store default (source: "product" or "store").
curl -s "$API/deposits/products/88001" -H "Authorization: Bearer $KEY"
# 200
{"product_id": 88001, "title": null, "source": "store", "rule": {"mode": "fixed", "amount": "200", "per": "unit"}}
PUT /api/v1/deposits/products/{productId} #
Gives a product its own rule. Body: rule ({mode, amount, per}) and an optional title for the list.
mode:off,fixed(an amount) orpercent(of the rental’s unit price, at most 100).per:unit(times the quantity),line(once per cart line) ororder(joins the one deposit per order).amountis required unlessmodeisofforperisorder.
curl -s -X PUT "$API/deposits/products/88001" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"rule": {"mode": "percent", "amount": "25", "per": "line"}, "title": "Party tent 6×12 m"}'
# 200
{"product_id": 88001, "title": "Party tent 6×12 m", "rule": {"mode": "percent", "amount": "25", "per": "line"}, "warning": null}
warning means the rule is saved but the checkout can’t use it yet: the app retries in the background. 400 invalid (data.field: rule.mode or rule.amount).
DELETE /api/v1/deposits/products/{productId} #
Puts the product back on the store default: {"product_id": 88001, "removed": true}.
