Stateset One provides a REST and GraphQL API for Returns Management.

The Returns Management module in Stateset includes various objects that facilitate the returns processes. These objects typically encompass:

  • Return
  • Return Line Items
  • Orders
  • Refunds

Returns Management Overview

Returns are an inevitable part of the eCommerce business. Customers may request returns for a variety of reasons, such as receiving a damaged or defective item, or simply changing their mind about a purchase. Regardless of the reason, it is important for businesses to have a streamlined process in place to manage returns efficiently and effectively. This helps in enhancing customer experience and building brand loyalty.

Challenges with Returns Management

Returns management can be a complex and time-consuming process. It involves multiple steps, such as generating return labels, creating returns in the system, and processing refunds. These steps are often manual and require significant time and effort. This can lead to delays in processing returns, resulting in customer dissatisfaction and loss of revenue.

Stateset’s Returns Management Solution

Stateset’s Returns Management solution automates the entire returns process, from generating return labels to processing refunds. This helps in streamlining the process and reducing the time and effort required to manage returns. The solution leverages the Temporal workflow orchestration framework to automate the various steps involved in returns management. This includes generating and emailing return labels, creating returns in Stateset, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. By automating the returns process, Stateset enables businesses to effectively manage and track returns, thereby enhancing customer experience and improving operational efficiency.

Quickstart Guide

1

Sign Up

Setup your company’s Stateset One instance by signing up at stateset.io/signup

2

Create Key

Create a new API Key in the Stateset Cloud Console cloud.stateset.com/api-keys

3

Install Node.js SDK

Install the stateset-node SDK in your project:

npm install stateset-node
4

Create a New Return


import { stateset } from 'stateset-node'('API_KEY');

const return = await stateset.returns.create({
id: 'R-123313',
order_id: 'O-12332312',
serial_number: 'st123976879tm',
'description:' 'Return for different type',
'status': 'NEW'
'reported_condition': 'A',
'tracking_number': '132908231098120921',
'zendesk_number': '123313',
'action_needed': 'Replacement'
'rma': 'R-123312',
'country': 'US'
});

Return Initiation

When a customer requests a return, the Returns Management workflow in Stateset is triggered. The workflow captures the necessary information from the customer, such as order details, reason for return, and any supporting documentation.

Return Record

Return Label Generation and Emailing

Using the captured information, the workflow generates a return label that includes the shipping address and other relevant details. The label is then emailed to the customer, providing clear instructions on how to return the item.

Creation of a Return in Stateset

Simultaneously, the workflow creates a new return in Stateset, associating it with the corresponding order and customer information. This allows for streamlined tracking and management of the return process within the Stateset platform.

Stateset Workflow using Temporal

Temporal is an open source programming model that can simplify your code, make your applications more reliable, and help you deliver more features faster. The temporal framework allows activities to be defined and workflows to execute them based on the state or specific signals. Temporal provides the workflow management engine to combine the power of serverless API calls with a deterministic scheduler for execution. By leveraging the Temporal workflow orchestration framework, Stateset automates the entire Returns Management (RMA) process. This includes generating and emailing return labels, creating returns in Stateset, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. This automation streamlines the return process, enhances customer experience, and enables businesses to effectively manage and track returns.

Here is an example of Stateset’s Return API using Temporal Worker & Workflow:

javascript

import { Worker } from '@temporalio/worker';
import { URL } from 'url';
import * as activities from './activities.js';

async function run() {

  const worker = await Worker.create({
    workflowsPath: new URL('./workflows/return-ticket-approved.js', import.meta.url).pathname,
    activities,
    taskQueue: 'stateset-returns-automation',
    namespace: 'stateset'
  });

  await worker.run();

}

run().catch((err) => {
  console.error(err);
  process.exit(1);
});

javascript
import { proxyActivities } from '@temporalio/workflow';
import * as wf from '@temporalio/workflow';

// Proxy Activities
const { generateResponse, createZendeskComment, createReturnRecord, generateUSLabel, generateCALabel, updateWorkflowId, updateMatch, cancelSubscription } = proxyActivities({
    startToCloseTimeout: '1 minute',
});

/** A workflow that simply calls an activity */
export async function returnApprovedWorkflow(body, ticket_id_int) {
    
    let workflow_state = [];
    var cancel_subscription = body.cancel_subscription;
    var condition = body.condition;
    var match = body.match;
    var country = body.country;

    // Generate Response
    await generateResponse(body);

    // Generate Label
    if (country = "US") {

        await generateUSLabel(ticket_id_int);

    } else {

        await generateCALabel(ticket_id_int);
    }

    // Create Return
    var return_id = await createReturnRecord(ticket_id_int);

    // Update Workflow Id
    await updateWorkflowId(return_id, wf.workflowInfo().workflowId);

    // Cance Subscription
    if (cancel_subscription) {

        await cancelSubscription(customer_email, ticket_id_int);

    };

    // Sleep
    await wf.sleep('3 days');

    // If Instant Refund and Conditon = A
    if (condition == "A" && match == true) {

        const matched_return = await updateMatch(return_id, wf.workflowInfo().workflowId);

        await refundOrder(order_id);
        
        await createZendeskComment(ticket_id_int, condition);

        return 'return_and_refund_processed';

    }

}

Search and Lookup Capabilities

The Returns Management workflow in Stateset incorporates search functionality powered by Algolia that enables easy retrieval of return information. Users can search for returns based on various criteria, such as serial number, RMA number, or order ID. This helps in quickly locating specific return records and accessing relevant details.

javascript
// Save the Return Record to the Algolia Index
    index.saveObject({
        objectID: return_record.insert_returns.returning[0].id,
        order_id: return_record.insert_returns.returning[0].order_id,
        description: return_record.insert_returns.returning[0].description,
        reported_condition: return_record.insert_returns.returning[0].reported_condition,
        status: return_record.insert_returns.returning[0].status,
        serial_number: return_record.insert_returns.returning[0].serial_number,
        tracking_number: return_record.insert_returns.returning[0].tracking_number,
        rma: return_record.insert_returns.returning[0].rma,
        country: return_record.insert_returns.returning[0].country
    })

Instant Refunds Processing

For eligible returns, the Returns Management workflow includes instant refund processing. Once the returned item is received and inspected, the workflow automatically initiates the refund process, facilitating timely and efficient reimbursement to the customer. This eliminates delays and enhances customer satisfaction by ensuring prompt resolution of return requests.

Integration with Zendesk or Gorgias

The workflow integrates with customer support platforms like Zendesk or Gorgias to streamline communication and updates. Upon generating the return label and initiating the return process, the workflow updates the respective ticketing system with tracking information. This ensures that customer support representatives have real-time visibility into the status of returns and can provide accurate updates to customers when needed.

Aftership Tracking

javascript

export default async function (req, res) {

  var newReturn = req.body.event.data.new;
  var timestamp = req.body.created_at;
  var event_id = newReturn.id;
  var order_id = newReturn.order_id;
  var serial_number = newReturn.serial_number;
  var rma = newReturn.rma;
  var email = newReturn.customerEmail;
  var tracking_number = newReturn.tracking_number;
  var token = process.env.AFTERSHIP_TOKEN

    try {

      // Notification
      let aftership_tracking_response = await fetch('https://api.aftership.com/v4/trackings', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'aftership-api-key': token
        },
        body: JSON.stringify({
          "tracking" : {
              "tracking_number": tracking_number,
              "slug": "fedex",
              "title": rma,
              "emails": [
                  "customer@gmail.com"
              ],
              "order_id": order_id,
              "custom_fields": {
                  "label_created_date": timestamp,
                  "customer_email": email,
                  "serial_number": serial_number,
                  "workflow_event_id": event_id,
              }
          }
      })
    })

      console.log(aftership_tracking_response);

      return res.status(200).json({ status: "AfterShip Tracking API Event Successfully Executed" });

  } catch (error) {
    return res.status(500).json({
      "error_code": "internal_error",
      "error_message": error.toString ? error.toString() : error
    })
  };
};

Refunds

Refunds describes the general data about the goods or services being refunded to your customers. For example, you might have multiple line items on an order, each would be a separate Refund Line Item. The Refund is corresponding to the metadata regarding Refunde Items. The Refund resource has two major components:

  • Transaction records of money returned to the customer
  • The line items included in the refund, along with restocking instructions

Before you create a refund, use the calculate endpoint to generate accurate refund transactions. Specify the line items that are being refunded, their quantity and restock instructions, and whether you’re refunding shipping costs. You can then use the response of the calculate endpoint to create the actual refund. When you create a refund using the response from the calculate endpoint, you can set additional options, such as whether to notify the customer of the refund. You can refund less than the calculated amount for either shipping or the line items by setting a custom value for the amount property.

Shopify refunds

Stateset Returns Automation integrates with Shopify’s native Return APIs. For more information see the Stateset Returns Automation App on the Shopify App Store: https://apps.shopify.com/stateset-returns-automation

Here is an example of how to process a Refund using the Shopify Returns API:

javascript

    try {
        const suggestedRefund = await getSuggestedRefund(
            returnId,
            returnLineItems,
            shop,
            accessToken
        );

        const returnQuery = gql`
            mutation returnRefundMutation(
                $returnLineItems: [ReturnRefundLineItemInput!]!, 
                $refundShipping: RefundShippingInput,
                $orderTransactions: [ReturnRefundOrderTransactionInput!]
                ) {
                returnRefund(
                    returnRefundInput: {
                        returnId: "${returnId}",
                        returnRefundLineItems: $returnLineItems,
                        refundShipping: $refundShipping,
                        orderTransactions: $orderTransactions
                    }
                )
                {
                    refund {
                    id
                    }
                    userErrors {
                    field
                    message
                    }
                }
            }`;

        const returnResponseJson: any = await ShopifyClient(
            shop,
            accessToken,
            returnQuery,
            {
                returnLineItems,
                refundShipping: {
                    fullRefund: true,
                    shippingRefundAmount: {
                        amount:
                            suggestedRefund?.shipping?.maximumRefundableSet
                                ?.shopMoney?.amount || 0,
                        currencyCode:
                            suggestedRefund?.shipping?.maximumRefundableSet
                                ?.shopMoney?.currencyCode || 'USD'
                    }
                },
                orderTransactions:
                    suggestedRefund?.suggestedTransactions?.map((item: any) => {
                        return {
                            transactionAmount: {
                                amount: item.amountSet?.shopMoney?.amount || 0,
                                currencyCode:
                                    item.amountSet?.shopMoney?.currencyCode ||
                                    'USD'
                            },
                            parentId: item.parentTransaction.id
                        };
                    }) || []
            }
        );

        console.log(
            returnResponseJson.returnRefund.userErrors,
            returnResponseJson.returnRefund
        );

        if (returnResponseJson.returnRefund.userErrors?.length) {
            const message =
                returnResponseJson.returnRefund.userErrors[0].message;

            res.status(500).send(message);
            return;
        }

        if (returnResponseJson?.returnRefund?.refund) {
            await updateReturn(id, {
                status: 'REFUNDED'
            });

            return res.status(200).json({
                ...returnResponseJson.returnRefund.refund,
                msg: 'Successful Refund Return'
            });
        }

        res.status(500).send('There is no refund Transaction');
    } catch (error: any) {
        console.log(error);
        res.status(500).send(error.message);
    }
});

If a refund includes shipping costs, or if you choose to refund line items for less than their calculated amount, then an order adjustment is created automatically to account for the discrepancy in the store’s financial reports.

WooCommerce Refunds

The return record in Stateset will include customer information such as the order id which is used to query the total order amount and tax amount. These values are used to calculate the total refund amount depending on the restocking fee. A refund can be placed via the Return record which will trigger a refund in WooCommerce and then Stripe. It may take a few days for the refund to appear on the customers debit card. The refund can be verified in Stateset by going to the Stripe returns list view. The condition and rationale from the return record can also be sent back to Zendesk from Stateset as a private message for the CSR.

javascript

// refund for the item being returned
var refund_line_item = {
   "id": item_id,
   "quantity": 1,
   "refund_total": item_total - restocking_fee,
   "refund_tax": refund_tax_line_item_items
 };
 
// Process Refund Automatically
// Automated Refund Data
const data = {
    "api_refund": true,
    "reason": reason_category,
    "line_items": refund_line_items
};


// POST Request Options
var requestOptions = {
    method: 'POST',
    headers: {
            'Content-Type': 'application/json'
        },
    body: JSON.stringify(data)
};

// Process Refund
await fetch(`https://ecommerce.com/wp-json/wc/v3/orders/${order_id_int}/refunds`, requestOptions)
        .then(response => response.json())
        .then(json => {})

Returns Support

If you have any questions or need help, please contact us at: support@stateset.io