Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openshiporg/openfront/llms.txt
Use this file to discover all available pages before exploring further.
Openfront provides a sophisticated claims and returns system that handles the complete lifecycle of product returns, replacements, and refunds. The system tracks items, manages inventory, processes refunds, and maintains detailed audit trails.
Claims Architecture
The claims system consists of three main components:
- Claim Orders - Container for the claim with type and status
- Claim Items - Individual items being claimed
- Returns - Physical return of products
Claim Orders
Claim orders represent customer requests for returns or replacements:
ClaimOrder {
type: "replace" | "refund" // What customer wants
paymentStatus: "na" | "not_refunded" | "refunded"
fulfillmentStatus: "not_fulfilled" | "partially_fulfilled" | "fulfilled"
metadata: json
// Relationships
order: → Order // Original order
returnOrder: → Return // Associated return
claimItems: [→ ClaimItem] // Items being claimed
additionalItems: [→ OrderLineItem] // Replacement items
fulfillments: [→ Fulfillment] // Replacement shipments
}
Claim Types
Replace - Customer receives replacement product:
- Original item returned
- New item shipped
- No refund processed
- Useful for defective or wrong items
Refund - Customer receives money back:
- Original item returned
- Refund processed to payment method
- No replacement shipped
- Useful for unwanted items
Creating Claims
Step 1: Identify Order and Items
Customer initiates claim for specific items:
query GetOrderForClaim {
order(where: { id: "order_id" }) {
id
displayId
status
lineItems {
id
title
quantity
variant {
id
sku
title
}
}
}
}
Step 2: Create Claim Order
Initiate the claim:
mutation CreateClaim {
createClaimOrder(data: {
type: "refund"
order: { connect: { id: "order_id" } }
claimItems: {
create: [
{
reason: "wrong_item"
note: "Received blue shirt instead of black"
quantity: 1
item: { connect: { id: "line_item_id" } }
variant: { connect: { id: "variant_id" } }
}
]
}
}) {
id
type
claimItems {
id
reason
quantity
}
}
}
Step 3: Create Return
Track physical return of products:
mutation CreateReturn {
createReturn(data: {
order: { connect: { id: "order_id" } }
claimOrder: { connect: { id: "claim_id" } }
status: "requested"
returnItems: {
create: [
{
quantity: 1
item: { connect: { id: "line_item_id" } }
}
]
}
}) {
id
status
returnItems {
id
quantity
}
}
}
Claim Items
Detailed information about items being claimed:
ClaimItem {
reason: "missing_item" | "wrong_item" | "production_failure" | "other"
note: string // Customer explanation
quantity: integer // Number of items
claimOrder: → ClaimOrder
item: → OrderLineItem // Original line item
variant: → ProductVariant // Product variant
images: [→ ClaimImage] // Evidence photos
tags: [→ ClaimTag] // Classification tags
}
Claim Reasons
- missing_item - Item not received
- wrong_item - Incorrect product sent
- production_failure - Defective or damaged
- other - Other reasons (see note)
Adding Evidence
Customers can attach photos:
mutation AddClaimImage {
createClaimImage(data: {
url: "https://cdn.store.com/claims/damage-photo.jpg"
claimItem: { connect: { id: "claim_item_id" } }
}) {
id
url
}
}
Tagging Claims
Categorize claims for analysis:
mutation TagClaim {
createClaimTag(data: {
value: "shipping_damage"
claimItem: { connect: { id: "claim_item_id" } }
}) {
id
value
}
}
Return Processing
Manage the physical return of products:
Return {
status: "requested" | "received" | "requires_action" | "canceled"
refundAmount: integer // Amount to refund
receivedAt: timestamp // When items received
metadata: json
order: → Order
returnItems: [→ ReturnItem]
refund: → Refund // Processed refund
claimOrder: → ClaimOrder
reason: → ReturnReason // Categorization
location: → Location // Return destination
}
Return Workflow
Customer Initiates Return
Customer requests return through claims system
Provide shipping label for return:
const label = await createShippingLabel({
order: returnOrder,
type: 'return',
fromAddress: order.shippingAddress,
toAddress: warehouse.address,
});
mutation UpdateReturn {
updateReturn(
where: { id: "return_id" }
data: {
status: "shipped"
trackingNumber: "1Z999AA10123456784"
}
) {
id
status
trackingNumber
}
}
Warehouse receives and inspects:
mutation ReceiveReturn {
updateReturn(
where: { id: "return_id" }
data: {
status: "received"
receivedAt: "2024-03-15T10:30:00Z"
location: { connect: { id: "location_id" } }
}
) {
id
status
receivedAt
}
}
Process Refund or Replacement
Complete the claim based on type
Return Items
Track individual items in returns:
ReturnItem {
quantity: integer
isRequested: boolean
receivedQuantity: integer
note: string
return: → Return
item: → OrderLineItem
}
Partial Returns
Handle returns where not all items received:
mutation UpdateReturnItem {
updateReturnItem(
where: { id: "return_item_id" }
data: {
receivedQuantity: 1
note: "Only 1 of 2 items received"
}
) {
id
quantity
receivedQuantity
note
}
}
Refund Processing
Process refunds for returned items:
Refund {
amount: integer
reason: string
note: string
order: → Order
payment: → Payment
return: → Return
}
Creating Refunds
mutation ProcessRefund {
createRefund(data: {
amount: 9900
reason: "Customer return"
note: "Item returned in good condition"
order: { connect: { id: "order_id" } }
payment: { connect: { id: "payment_id" } }
return: { connect: { id: "return_id" } }
}) {
id
amount
reason
}
}
Refund to Payment Method
Process refund through payment provider:
import { refundPaymentFunction } from '@/features/integrations/payment';
async function processRefund(refund: Refund) {
const payment = refund.payment;
const provider = payment.paymentProvider;
// Get the adapter for this provider
const adapter = await getPaymentAdapter(provider.code);
// Process refund through provider
const result = await adapter.refundPaymentFunction({
paymentId: payment.providerId,
amount: refund.amount,
});
// Update claim status
await updateClaimOrder(refund.order.claimOrder.id, {
paymentStatus: 'refunded',
});
return result;
}
Replacement Processing
Handle product replacements:
Adding Replacement Items
mutation AddReplacementItem {
updateClaimOrder(
where: { id: "claim_id" }
data: {
additionalItems: {
create: [
{
title: "Black T-Shirt - Medium"
quantity: 1
variant: { connect: { id: "correct_variant_id" } }
order: { connect: { id: "order_id" } }
}
]
}
}
) {
id
additionalItems {
title
quantity
}
}
}
Fulfilling Replacements
Ship replacement items:
mutation CreateReplacementFulfillment {
createFulfillment(data: {
claimOrder: { connect: { id: "claim_id" } }
items: {
create: [
{
quantity: 1
item: { connect: { id: "additional_item_id" } }
}
]
}
}) {
id
trackingNumber
items {
quantity
}
}
}
Return Reasons
Categorize returns for analysis:
ReturnReason {
value: string
label: string
description: string
returns: [→ Return]
}
Common Return Reasons
mutation CreateReturnReasons {
createReturnReason(data: {
value: "defective"
label: "Defective Product"
description: "Product is damaged or not working"
}) { id }
createReturnReason(data: {
value: "wrong_item"
label: "Wrong Item"
description: "Received different product than ordered"
}) { id }
createReturnReason(data: {
value: "not_as_described"
label: "Not As Described"
description: "Product differs from description"
}) { id }
createReturnReason(data: {
value: "changed_mind"
label: "Changed Mind"
description: "Customer no longer wants product"
}) { id }
}
Claims Dashboard
View and manage all claims:
query ClaimsList {
claimOrders(
orderBy: [{ createdAt: desc }]
take: 20
) {
id
type
paymentStatus
fulfillmentStatus
createdAt
order {
displayId
email
}
claimItems {
id
reason
quantity
item {
title
}
}
}
}
Filtering Claims
query FilteredClaims($type: String, $status: String) {
claimOrders(
where: {
AND: [
{ type: { equals: $type } }
{ paymentStatus: { equals: $status } }
]
}
) {
id
type
paymentStatus
order {
displayId
}
}
}
Inventory Updates
Claims automatically update inventory:
Return Received
When items are received, inventory increases:
// Automatically creates stock movement
{
type: "return",
quantity: 1,
reason: "Customer return",
note: "Return ID: ret_123, Claim ID: claim_456"
}
Replacement Shipped
When replacement ships, inventory decreases:
// Automatically creates stock movement
{
type: "adjustment",
quantity: -1,
reason: "Claim replacement",
note: "Claim ID: claim_456"
}
Best Practices
Claims Policy
- Clearly communicate return windows
- Define acceptable return conditions
- Specify who pays return shipping
- Set expectations for refund timing
Processing Returns
- Inspect returned items promptly
- Document item condition
- Update inventory immediately
- Process refunds within stated timeframe
Customer Communication
- Acknowledge claim receipt
- Provide return shipping labels
- Send tracking for replacements
- Notify when refunds are processed
Data Analysis
- Track return reasons
- Identify problem products
- Monitor return rates by category
- Use insights to improve products
Analytics and Reporting
Return Rate by Product
query ProductReturnRates {
products {
id
title
productVariants {
sku
claimItems {
id
reason
}
}
}
}
Common Return Reasons
function analyzeReturnReasons(claims: ClaimOrder[]) {
const reasons = claims.flatMap(c =>
c.claimItems.map(i => i.reason)
);
const counts = reasons.reduce((acc, reason) => {
acc[reason] = (acc[reason] || 0) + 1;
return acc;
}, {} as Record<string, number>);
return Object.entries(counts)
.sort(([,a], [,b]) => b - a)
.map(([reason, count]) => ({ reason, count }));
}