v2.0

GoRules Version 2 is here - redesigned, now with managed cloud.GoRules Version 2 is here!

Watch the launch videoWatch

Returns and Refund Policy

Automated system that determines return eligibility, responsibility, and refund calculations based on purchase conditions and seller policies.

Solution

This policy enforcement system streamlines the returns process by evaluating multiple factors to determine eligibility and responsibility. The system first checks if a return request falls within the seller's specified time window and meets their return policy requirements. For eligible returns, it identifies whether the responsibility lies with the buyer, seller, or platform based on the reported issue and product condition.

Once responsibility is established, the system calculates the appropriate refund amount, factoring in potential restocking fees when applicable. It also determines whether return shipping costs should be covered and by which party. The system provides clear explanations at each decision point and estimates processing times based on the responsible party. This creates transparency for all stakeholders while ensuring consistent application of marketplace policies across all transactions.

How it works

The decision graph processes return requests through three interconnected nodes:

  1. Return Eligibility Assessment: Evaluates if the return falls within the allowed timeframe (standard or extended), checks if returns are permitted by the seller's policy, and considers the reason for the return.

  2. Responsibility Determination: Assigns responsibility to the appropriate party (buyer, seller, platform, or shared) based on the return reason, item condition, and eligibility determination. For example, damaged new items are the seller's responsibility, while "changed mind" returns are the buyer's responsibility.

  3. Refund Calculation: Computes the refund amount based on eligibility and responsibility, applying restocking fees when appropriate. It also determines whether return shipping costs are covered and estimates processing time based on the responsible party.

Where teams use it

  • E-commerce marketplaces
  • Retail return centers
  • Online shopping platforms
  • Drop-shipping businesses
  • Third-party seller management
  • Multi-vendor retail solutions
  • Customer service automation

Inside the decision model

Returns and Refund Policy ships as a JDM decision graph with 4 nodes, 2 decision tables and 13 rules. Download it, load it into GoRules, and run it as-is on Zen Engine.

Decision graph4 nodes · read-only
input requesttable returnEligibilitytable responsibilityDeterminationexpression refundCalculation
01

Request

input

A return request carries the flat fields returnReason, daysSincePurchase, originalPrice, and itemCondition alongside sellerPolicy with returnsAllowed, returnWindow, restockingFeePercent, and freeReturnShipping. The orderInfo, buyerInfo, and productDetails blocks travel with the request for context.

Sample requestJSON
{
  "orderInfo": {
    "orderId": "ORD-12345",
    "purchaseDate": "2023-10-15"
  },
  "returnReason": "damaged",
  "daysSincePurchase": 25,
  "originalPrice": 89.99,
  "itemCondition": "new",
  "sellerPolicy": {
    "returnsAllowed": true,
    "returnWindow": 30,
    "restockingFeePercent": 15,
    "freeReturnShipping": false
  },
  "buyerInfo": {
    "id": "USR-789",
    "returnHistory": {
      "totalReturns": 3,
      "recentDisputes": 0
    }
  },
  "productDetails": {
    "category": "electronics",
    "isWarrantyActive": true
  }
}
02

Return Eligibility

table

Eligibility is decided first, with a first hit policy over daysSincePurchase, sellerPolicy.returnsAllowed, and returnReason. Within 30 days and with returns allowed, the reasons 'damaged', 'defective', and 'wrong_item' produce the code 'eligible', while 'changed_mind' maps to 'eligible_restocking_fee'; between 30 and 60 days only 'damaged' and 'defective' qualify as 'eligible_extended', anything past 60 days fails as 'ineligible_timeframe', returnsAllowed set to false fails as 'ineligible_non_returnable', and the blank row catches the rest as 'ineligible_other'.

The 30-day window is the standard return period across most of retail, and extending it to 60 days only for product faults mirrors how sellers separate goodwill remorse returns from defect claims that would surface later anyway. Cutting off entirely past 60 days bounds the seller's open liability, and letting sellerPolicy.returnsAllowed veto everything keeps final-sale merchandise enforceable in the same table.

Decision tablefirst hit policy
Days Since PurchasedaysSincePurchaseItem ReturnablesellerPolicy.returnsAllowedReturn ReasonreturnReasonIs EligiblereturnStatus.isEligibleEligibility CodereturnStatus.codeEligibility MessagereturnStatus.message
< 30true'damaged', 'defective', 'wrong_item'true'eligible''The return is within policy timeframe and eligible for processing.'
< 30true'changed_mind'true'eligible_restocking_fee''Return is eligible but subject to restocking fee per seller policy.'
> 30, <= 60true'damaged', 'defective'true'eligible_extended''Extended return period applies for product issues.'
> 60--false'ineligible_timeframe''Return period has expired.'
-false-false'ineligible_non_returnable''Item is marked as non-returnable in seller policy.'
---false'ineligible_other''Return does not meet eligibility criteria.'
03

Responsibility Determination

table

Fault assignment reads returnReason, itemCondition, and the upstream returnStatus.isEligible under a first hit policy. Eligible 'damaged' or 'defective' returns on 'new' or 'like_new' items assign resolution.responsibleParty to 'seller', 'wrong_item' is also the seller's fault, 'damaged_in_transit' goes to 'platform' under shipping protection, 'changed_mind' lands on the 'buyer', and 'damaged' or 'defective' claims on 'used' or 'refurbished' items resolve as 'shared'. Ineligible returns get 'none' with refundApproved false, and the fallback row escalates unmatched cases to 'platform' review without approving a refund.

This split follows how marketplaces genuinely allocate return costs: sellers own defects on goods sold as new, transit damage sits with whoever runs the shipping program, and remorse returns are the buyer's expense. The 'shared' outcome for used and refurbished items is a pragmatic choice because pre-existing wear makes fault hard to attribute, and defaulting unknown combinations to platform review rather than an automatic refund keeps edge cases with a human.

Decision tablefirst hit policy
Return ReasonreturnReasonItem ConditionitemConditionIs EligiblereturnStatus.isEligibleResponsible Partyresolution.responsiblePartyRefund Approvedresolution.refundApprovedResponsibility Noteresolution.note
'damaged', 'defective''new', 'like_new'true'seller'true'Seller is responsible for product issues on new items.'
'wrong_item'-true'seller'true'Seller is responsible for shipping incorrect item.'
'damaged_in_transit'-true'platform'true'Platform shipping protection covers transit damage.'
'changed_mind'-true'buyer'true'Buyer is responsible for return costs when changing mind.'
'damaged', 'defective''used', 'refurbished'true'shared'true'Responsibility is shared for used/refurbished items with issues.'
--false'none'false'No refund applicable for ineligible returns.'

+1 more row in the downloadable template

04

Refund Calculation

expression

Money and logistics resolve in one expression step. refundAmount pays the full originalPrice when resolution.refundApproved is true, discounts it by sellerPolicy.restockingFeePercent when the code is 'eligible_restocking_fee', and drops to 0 otherwise; returnShippingCovered and refundShipping are true whenever the responsibleParty is 'seller' or 'platform', so buyers only pay return postage on their own remorse returns. processingTimeEstimate maps to 7, 5, or 3 days by responsible party, with 14 days for unapproved cases that need review.

Expressions4 fields
refundAmountresolution.refundApproved == true ? (returnStatus.code == 'eligible_restocking_fee' ? originalPrice * (1 - sellerPolicy.restockingFeePercent / 100) : originalPrice) : 0
refundShippingresolution.responsibleParty == 'seller' or resolution.responsibleParty == 'platform'
returnShippingCoveredresolution.responsibleParty == 'seller' or resolution.responsibleParty == 'platform'
processingTimeEstimateresolution.refundApproved == true ? (resolution.responsibleParty == 'platform' ? 7 : resolution.responsibleParty == 'seller' ? 5 : 3) : 14

Make this template
your own.

Load Returns and Refund Policy into GoRules, adjust the rules to your policy, and ship it behind your own API.