Submit a Return
Call /v1/return when a customer initiates a return. Pinch evaluates the return against your Returns workflow and emits a decision for each returned line item.
Request
POST /v1/return HTTP/1.1
Host: api.pinch.ai
Authorization: {api-key}
Content-Type: application/json
Body
| Field | Type | Required | Description |
|---|---|---|---|
providerOrderId | string | yes | The order this return is against. Must match a previously sent order. |
providerReturnId | string | yes | Your platform's return identifier. Unique within your account. |
status | string | yes | REQUESTED, APPROVED, RECEIVED, COMPLETED, CANCELLED. |
reason | string | yes | Customer-provided reason at the return level. |
returnMethod | object | yes | { returnMethod } — Drop-Off, Pickup, In-Store. |
refundMode | object | yes | { refundMode } — ORIGINAL_PAYMENT, STORE_CREDIT, EXCHANGE. |
returnedLineItems | array | yes | See returnedLineItems. |
deviceFingerprints | array | recommended | Same shape as the Order API. |
timestamp | string | yes | Epoch ms as a string. |
Returned line items
Each entry in returnedLineItems:
| Field | Type | Required | Description |
|---|---|---|---|
lineItem.identifiers | array | yes | Same identifier shape as the Order API. Must reference an item from the original order. |
category | string | no | Product category. |
quantity | string | yes | Quantity being returned. |
reason | string | yes | Per-item reason. |
Example request
- curl
- Node
- Python
curl https://api.pinch.ai/v1/return \
-H "Authorization: {api-key}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"providerOrderId": "MC229151G",
"providerReturnId": "WETIIO2PG",
"status": "REQUESTED",
"reason": "Return - No longer want",
"returnMethod": { "returnMethod": "Drop-Off" },
"refundMode": { "refundMode": "ORIGINAL_PAYMENT" },
"returnedLineItems": [
{
"lineItem": {
"identifiers": [
{ "identifierType": "UPC", "identifier": "26SDSDSMC30" }
]
},
"category": "Dress",
"quantity": "1",
"reason": "Return - No longer want"
}
],
"deviceFingerprints": [{ "deviceIdentifier": "abc123visitorId" }],
"timestamp": "1721050915000"
}'
const response = await fetch("https://api.pinch.ai/v1/return", {
method: "POST",
headers: {
"Authorization": process.env.PINCH_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
providerOrderId: "MC229151G",
providerReturnId: "WETIIO2PG",
status: "REQUESTED",
reason: "Return - No longer want",
returnMethod: { returnMethod: "Drop-Off" },
refundMode: { refundMode: "ORIGINAL_PAYMENT" },
returnedLineItems: [/* ... */],
deviceFingerprints: [{ deviceIdentifier: visitorId }],
timestamp: String(Date.now())
})
});
const decision = await response.json();
import os, requests, time
response = requests.post(
"https://api.pinch.ai/v1/return",
headers={
"Authorization": os.environ["PINCH_API_KEY"],
"Content-Type": "application/json",
"Accept": "application/json",
},
json={
"providerOrderId": "MC229151G",
"providerReturnId": "WETIIO2PG",
"status": "REQUESTED",
"reason": "Return - No longer want",
"returnMethod": {"returnMethod": "Drop-Off"},
"refundMode": {"refundMode": "ORIGINAL_PAYMENT"},
"returnedLineItems": [...],
"deviceFingerprints": [{"deviceIdentifier": visitor_id}],
"timestamp": str(int(time.time() * 1000)),
},
)
decision = response.json()
Response
The response includes a decision per returned line item.
{
"providerReturnId": "WETIIO2PG",
"pinchReturnId": "pret_3f8a1c",
"returnedLineItems": [
{
"lineItem": {
"identifierType": "UPC",
"identifier": "26SDSDSMC30"
},
"decisionType": "APPROVE/DECLINE/REVIEW",
"decision": "APPROVE",
"subDecision": "High Customer Value",
"reason": "Customer Value Per Email exceeds VIP threshold",
"abuseScore": 18
}
]
}
| Field | Description |
|---|---|
providerReturnId | Echo of your providerReturnId. |
pinchReturnId | Pinch's internal return identifier. |
returnedLineItems[].decision | APPROVE, DECLINE, or REVIEW. |
returnedLineItems[].subDecision | The specific workflow branch that matched. |
returnedLineItems[].reason | Why this decision was made. |
returnedLineItems[].abuseScore | 0–100 abuse risk score at return time. |
Decision semantics
| Decision | What you should do |
|---|---|
APPROVE | Accept the return and process the refund per your normal flow. |
DECLINE | Block the return. Your RMS should refuse to issue a return label or refund. |
REVIEW | Route to manual review. The return appears in the Pinch dashboard's Review queue with AI Analysis. Approve or deny from there before processing. |
In a typical Shopify deployment, you don't act on the response directly — Pinch writes an customer tag (e.g. Pinch - Deny : Egregious) that your RMS reads. The API response is most useful for custom integrations.
Errors
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Missing required field. |
| 401 | unauthenticated | API key missing or invalid. |
| 404 | order_not_found | The referenced providerOrderId doesn't exist in Pinch. Send the order first. |
| 409 | duplicate_return | providerReturnId already exists. |
| 422 | unprocessable_entity | Field values failed validation. |
| 429 | rate_limited | Slow down. |
See also
- Order API — must be called first
- Disposition data guide — send disposition data once the return is received
- Review queue — what happens when a return is routed to Review