Two mutations record stock physically leaving and coming back: sendRentalSerials checks units out to the customer, returnRentalSerials takes them back in. They are the API behind the Rentals > Send and Rentals > Return screens, and they run the same code those screens run — so a warehouse scanner app driving this API and a member of staff using the admin cannot get out of step.
sendRentalSerials needs SalesIgniter_Rental::send; returnRentalSerials needs SalesIgniter_Rental::return. Holding one does not grant the other, which is usually what you want: a returns desk should not be able to send stock out.
Sending units out #
mutation SendOut {
sendRentalSerials(input: {
order_id: 4571
product_id: 123
serials: ["CR6-0004", "CR6-0011"]
}) {
success
message
shipment_id
reservations {
id
qty
qty_shipped
qty_returned
serials_shipped
ship_date
state
}
}
}
{
"data": {
"sendRentalSerials": {
"success": true,
"message": "Serials sent successfully",
"shipment_id": 812,
"reservations": [
{
"id": 8123,
"qty": 2,
"qty_shipped": 2,
"qty_returned": 0,
"serials_shipped": ["CR6-0004", "CR6-0011"],
"ship_date": "2026-10-03 09:14:00",
"state": "OUT"
}
]
}
}
}
- The number of serials is the quantity. Two entries sends two units. There is no separate quantity argument.
- Sending creates a Magento shipment and returns its id. Pass
shipment_idyourself to attach to an existing one instead — useful when a single physical shipment covers several products. - The serials are marked as out, which takes them off the rentable fleet until they come back.
reservationsis re-read after the write, so the counts andstateyou get back are the new truth rather than what you sent.
Products that are not serial-tracked #
serials is still required, and the count is still the quantity — pass one placeholder entry per unit. To send three untracked lighting stands:
sendRentalSerials(input: {
order_id: 4571
product_id: 456
serials: ["STAND-4571-1", "STAND-4571-2", "STAND-4571-3"]
}) { success reservations { qty_shipped } }
Make placeholders unique per unit, and reproducible. They are stored against the booking as though they were serials, and returnRentalSerials finds the booking by matching them — so three entries all reading "STAND" cannot be returned one at a time, and a placeholder you cannot regenerate later cannot be returned at all. Deriving them from the order and line number, as above, works well.
Taking units back #
Returning needs only the serials. The booking each one belongs to is found from the serial itself, so a returns desk scanning a pile of kit does not have to know which order any of it came from — which is the whole point.
mutation TakeBack {
returnRentalSerials(input: {
serials: ["CR6-0004", "CR6-0011", "STAND-4571-1"]
}) {
success
message
reservations {
id
order_increment_id
qty_shipped
qty_returned
serials_returned
return_date
state
}
}
}
- Serials from several different orders can be returned in one call.
reservationscomes back with every booking that was touched. - The units go back onto the rentable fleet, and
statebecomesRETURNEDonce a booking’s last unit is in. - A partial return is normal: return what is in front of you and the booking stays
OUT(orOVERDUE) until the rest arrives. - A serial that matches no open booking is not an error —
successistrueand it simply contributes nothing toreservations. Scanning something twice, or scanning a unit that was already booked in, is a normal thing to happen at a returns desk and does not need to fail the whole batch.
When it goes wrong #
Bad arguments are rejected before anything is written: an empty serials list, a blank entry inside it, or a non-positive order_id/product_id all come back as graphql-input errors with nothing recorded. Anything the send/return processor itself refuses — no matching booking, more units than the booking holds — comes back the same way, carrying the processor’s own message. success is never true on a failure.
One caution: lines split across bookings #
If a single order line is held by more than one booking for the same product — two MSI sources, or a line split across depots — a send addressed to that order and product applies the full quantity to each of those bookings. Send against such an order one booking at a time, or check reservations in the response and correct before the kit leaves. This behaviour is inherited from the existing send/return processor and is the same through the admin screens and the REST API.
Use rentalOrders to see, before sending, whether a line has one booking or several.
