Returns Guide
Check what an order line can be returned, then open a return request
The Returns API lets you check whether the lines of an order can be returned and open a return
request for the ones that can. A request opens with every line PENDING; Sibi staff then approve or
deny each line, and the outcome arrives on webhooks — the API itself only requests and reads.
Benefits
- Check before you ask: See per-line returnability, the window that applies, and any conditions before opening a request
- Return part of an order: A request covers one or more lines, each with its own quantity, condition, and reason
- Per-line outcomes: Staff approve or deny each line independently, so one request can end with some lines approved and others denied
- Know the result: Approvals and denials arrive on the return-request webhook events
Core Concepts
Return Eligibility
Per-line returnability for an order: whether each line can be returned, the policy window, and any conditions that apply at intake.
Return Request
A request to return one or more lines of an order. It has no request-level status — status is per line.
Item Status
Each requested line is PENDING, APPROVED, or DENIED, derived from the latest decision on it.
Decisions
Sibi staff approve or deny each line. The outcome is announced on the return-request webhook events.
Checking Eligibility
GET https://api.sibipro.com/orders/{orderId}/returns/eligibility with a read:returns scoped
REST API token. The response is index-aligned to the order’s line
items: entry index is the verdict for that position in the order.
curl \
--request GET \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
'https://api.sibipro.com/orders/SIBI-12345678/returns/eligibility'
const response = await fetch(
`https://api.sibipro.com/orders/${encodeURIComponent(orderId)}/returns/eligibility`,
{ headers: { Authorization: `Bearer ${yourApiKey}` } },
);
const { items } = await response.json();
{
"items": [
{
"index": 0,
"orderLineItemId": "OLI-0001",
"productId": "GDF510PSRSS",
"status": "RETURNABLE",
"isReturnable": true,
"reasons": [],
"conditions": [{ "code": "MUST_BE_UNOPENED", "message": "Item must be unopened." }],
"policy": {
"partner": "ge",
"windowDays": 30,
"daysRemaining": 12,
"windowEndsAt": "2026-09-16T00:00:00.000Z",
"restockingFee": "5–10% restocking fee",
"summary": "Unopened appliances may be returned within 30 days of delivery."
}
}
]
}
A status of RETURNABLE means the line can be returned (check conditions for caveats verified at
intake); NOT_RETURNABLE means it cannot (see reasons); UNKNOWN means no policy answer — route
it to support.
Opening a Return Request
POST https://api.sibipro.com/orders/{orderId}/returns with a create:returns scoped token. The
body names the lines to return; each line carries a quantity, a condition, and a requestReason.
curl \
--request POST \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"items": [
{
"orderLineItemId": "OLI-0001",
"quantity": 1,
"condition": "UNOPENED",
"requestReason": "Ordered the wrong size"
}
]
}' \
https://api.sibipro.com/orders/SIBI-12345678/returns
const response = await fetch(`https://api.sibipro.com/orders/${encodeURIComponent(orderId)}/returns`, {
method: 'POST',
headers: {
Authorization: `Bearer ${yourApiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
items: [
{
orderLineItemId: 'OLI-0001',
quantity: 1,
condition: 'UNOPENED',
requestReason: 'Ordered the wrong size',
},
],
}),
});
const returnRequest = await response.json();
condition is one of UNOPENED, OPENED-UNUSED, INSTALLED, or DAMAGED. A successful call
returns 201 with the request; every line starts PENDING:
{
"id": "RET-12345XYZ",
"orderId": "SIBI-12345678",
"createdAt": "2026-09-04T15:30:45.123Z",
"updatedAt": "2026-09-04T15:30:45.123Z",
"items": [
{
"orderLineItemId": "OLI-0001",
"quantity": 1,
"condition": "UNOPENED",
"requestReason": "Ordered the wrong size",
"status": "PENDING",
"latestDecision": null
}
]
}
Reading Return Requests
GET https://api.sibipro.com/orders/{orderId}/returns lists the return requests on an order,
newest first, with a read:returns scoped token. Each item carries its per-line status, and once a
line is decided, its latestDecision.
curl \
--request GET \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
'https://api.sibipro.com/orders/SIBI-12345678/returns'
const response = await fetch(
`https://api.sibipro.com/orders/${encodeURIComponent(orderId)}/returns`,
{ headers: { Authorization: `Bearer ${yourApiKey}` } },
);
const { items } = await response.json();
{
"items": [
{
"id": "RET-12345XYZ",
"orderId": "SIBI-12345678",
"createdAt": "2026-09-04T15:30:45.123Z",
"updatedAt": "2026-09-05T09:12:03.900Z",
"items": [
{
"orderLineItemId": "OLI-0001",
"quantity": 1,
"condition": "UNOPENED",
"requestReason": "Ordered the wrong size",
"status": "DENIED",
"latestDecision": {
"outcome": "DENIED",
"denialReason": "Item is outside the return window",
"decidedAt": "2026-09-05T09:12:03.900Z"
}
}
]
}
]
}
An order with no return requests returns an empty items list. An empty list always means the
order genuinely has none: if the return data cannot be read from an upstream dependency, the
endpoint returns 503 SERVICE_UNAVAILABLE rather than an empty list (see Errors).
Learning the Outcome
Decisions are made by Sibi staff, not through this API. Subscribe to the return-request webhook events to learn when a line is approved or denied:
order.return-request.created— a request was openedorder.return-request.item-approved— a line was approvedorder.return-request.item-denied— a line was denied
See Order Return Requests events for the payloads. You can also
poll GET /orders/{orderId}/returns to read the current per-line status.
Errors
A request for a line that cannot be returned is refused with a 400 carrying one of:
| Code | Meaning |
|---|---|
RETURN_INVALID_CONDITION |
The condition is not one of the accepted values |
RETURN_INVALID_QUANTITY |
The quantity is not a positive whole number |
RETURN_DUPLICATE_LINE |
The same order line appears more than once in the request |
RETURN_LINE_NOT_ON_ORDER |
The orderLineItemId is not a line on the order |
RETURN_ITEM_NOT_ELIGIBLE |
Policy does not allow returning this line |
RETURN_QUANTITY_EXCEEDED |
The requested quantity exceeds what remains returnable on the line |
An order that does not exist or is not visible to the caller returns 404 ORDER_NOT_FOUND on every
endpoint, so the API cannot be used to discover which order ids exist. Authentication and scope
failures follow the usual codes; see Making a REST Request. Every
returns endpoint requires a REST API token: a token issued for the GraphQL API receives a 403 with
code REST_TOKEN_REQUIRED.
If the return data is temporarily unreadable upstream, the read endpoints
(GET /orders/{orderId}/returns and GET /orders/{orderId}/returns/eligibility) return
503 SERVICE_UNAVAILABLE. The order exists and is visible — only the read failed — so the request
can be retried.
{
"code": "RETURN_ITEM_NOT_ELIGIBLE",
"message": "This item is not eligible for return."
}
Testing
The Returns API is production-only — it has no test environment. Requests to
https://dev.sibi.pro/orders/{orderId}/returns*, and any request carrying the test header, are
refused with 403 NOT_AVAILABLE_IN_TEST.
Endpoints
Returns endpoints
Every endpoint with parameters, response schemas, and code samples.