Raise a Return
Raise a new return (RMA) request for one item of one of the customer's orders. The item must be return-eligible — check it with GET /api/shop/returnable-items first. The requested quantity (rma_qty) is capped server-side by the quantity the customer is actually allowed to return. The return starts in a Pending status.
Endpoint
POST /api/shop/returnsAuthentication
This endpoint requires an authenticated customer — send the storefront key and a customer Bearer token. See the Authentication page.
Request Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | application/json |
X-STOREFRONT-KEY | Yes | Your storefront API key |
Authorization | Yes | Bearer token (customer login required) |
Request Body
{
"order_id": 45,
"order_item_id": 78,
"rma_qty": 1,
"resolution_type": "return",
"rma_reason_id": 2,
"information": "Item arrived damaged.",
"package_condition": "open",
"custom_attributes": {
"1": "INV-9921",
"2": "morning"
},
"agreement": true
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
order_id | integer | Yes | Id of the order the item belongs to. |
order_item_id | integer | Yes | Id of the order item being returned — the orderItemId from returnable-items. This is the order line id, not the product id. |
rma_qty | integer | Yes | Quantity to return. Capped server-side by the returnable quantity. |
resolution_type | string | Yes | return or cancel_items. |
rma_reason_id | integer | Yes | Id of the chosen return reason — from return-reasons. |
information | string | No | Free-text note about the return. |
package_condition | string | No | Reported package condition — open or packed. Any other value is rejected. |
custom_attributes | object | Conditional | Answers to the return form's custom fields, keyed by field id — see List Return Custom Fields. Required when the store has custom fields marked isRequired. |
agreement | boolean | Yes | Must be true to confirm the return terms. |
Custom Fields
The store can configure additional questions the shopper answers while raising a return. Fetch them with GET /api/shop/return-custom-fields and send the answers in custom_attributes, keyed by the field id:
- every field with
isRequired: truemust be answered, otherwise the request is rejected selectandradioanswers must be one of the field's optionvaluesmultiselectandcheckboxanswers take a list of option values- the stored answers come back on the return as
customAttributes
Attaching Images
To attach evidence images, send the same fields as multipart/form-data with an images[] file field instead of a JSON body:
curl -X POST https://your-store.com/api/shop/returns \
-H "X-STOREFRONT-KEY: pk_storefront_..." \
-H "Authorization: Bearer <customer-token>" \
-F "order_id=45" \
-F "order_item_id=78" \
-F "rma_qty=1" \
-F "resolution_type=return" \
-F "rma_reason_id=2" \
-F "package_condition=open" \
-F "agreement=1" \
-F "custom_attributes[1]=INV-9921" \
-F "images[][email protected]" \
-F "images[][email protected]"Each file is checked against the mime types the store allows for returns (admin → Settings → RMA → Allowed file extension); an unsupported file rejects the whole request with 400. Images can only be attached while raising the return — there is no separate upload endpoint — and file uploads are REST-only, since a JSON GraphQL request cannot carry a file.
Response Fields (201 Created)
| Field | Type | Description |
|---|---|---|
id | integer | Return ID. |
orderId | integer | Id of the order the item belongs to. |
orderIncrementId | string | Human-readable order number. |
statusId | integer | Numeric status id — 1 (Pending) for a fresh return. |
statusTitle | string | Status label. |
statusColor | string | Hex color for the status badge. |
packageCondition | string | Reported package condition. |
information | string | The note supplied when raising the return. |
canClose | boolean | Whether the return can be closed. |
canReopen | boolean | Whether the return can be reopened. |
isExpired | boolean | Whether the return is past its action window. |
item | object | The returned item — id, order_item_id, sku, name, quantity, resolution, reason_id, reason, variant_id. |
images | array | Attached images (id, path, url). Empty when no files were sent. |
customAttributes | array | Answers to the return's custom fields — field_id, code, label, type, value. Empty when the store has no custom fields. |
messagesCount | integer | Number of conversation messages — 0 for a fresh return. |
createdAt | string | ISO 8601 creation timestamp. |
updatedAt | string | ISO 8601 last update timestamp. |
Status Codes
| Status | Meaning |
|---|---|
201 Created | Return raised; status is Pending. |
400 Bad Request | Item not eligible, invalid quantity, agreement not true, unknown package_condition, an unanswered required custom field, a value outside a field's options, or an unsupported image type. |
401 Unauthorized | Missing or invalid storefront key. |
403 Forbidden | Missing or invalid customer Bearer token. |
404 Not Found | The order does not exist or is not the customer's. |
Related Resources
- List Returnable Items — which order items are still eligible, and for how many units
- List Return Reasons — the reason ids to choose from
- List Return Custom Fields — the extra questions to answer in
custom_attributes - Cancel a Return — withdraw a return the customer raised
- Returns Overview — the returns menu overview, including the settings that gate it

