Views:

Overview

This North52 rules engine example implements a fraud detection and order management system for Shopify orders. Shopify sends information to Dataverse via a webhook. This triggers a Flow and calls a custom action which is bound to a North52 Formula. The rules are evaluated and if fraud or a problem customer is determined by the rules, North52 connects via the Shopify API to update the order.  

Key Features

  • Automated fraud prevention based on spending patterns
  • Risk-based decision making with different thresholds
  • Integration with Shopify using GraphQL APIs
  • Historical pattern analysis to identify unusual behavior
  • Manual review workflow for suspicious but not clearly fraudulent orders

This system helps prevent fraudulent orders while minimizing false positives by using the customer's own purchase history as a baseline.

Rules for Shopify integration

Rule #Description
1

Fraud Assessment - Evaluates the current order against the customer's historical patterns: High Risk (3x Average): If current order > 3× average order value:

  • Automatically cancels the order with reason "FRAUD"
  • Issues refund and restocks inventory
  • Updates order with "fraud-assessed" tag and cancellation note
2

Fraud Assessment - Evaluates the current order against the customer's historical patterns: Medium Risk (1.5x Average): If current order > 1.5× average order value:

  • Puts order on hold for manual review
  • Adds tags: "on-hold, manual-review, problem-customer"
  • Adds note requiring manual verification
3

Problem Customer Check - Queries the system for previous problem cases:

  • If customer has 2+ previous incidents, puts current order on hold regardless of amount
  • Uses the same hold process as medium-risk orders

 

North52 Decision Suite Solution

The North52 Decision Suite solution works like this:

  1. Flow to receive the webhook request from Shopify
  2. Custom Action with a parameter populated by the Flow with JSON from Shopify
  3. xCache values to store Shopify API key, and various GraphQL queries
  4. Formula bound to the Custom Action to process information, determine outcomes and update Shopify order via API
    • Initialize Variables - Extracts order ID, customer ID, and current order total from the incoming JSON payload
    • Fetch Customer Order History - Makes a GraphQL API call to Shopify to retrieve all previous orders for the customer (up to 250 orders)
    • Calculate Customer Metrics:
      • Total Order Value: Sums up the total amount from all previous orders
      • Average Order Value: Divides total by number of orders to get the customer's average spend
      • Fraud Assessment - Evaluates the current order against the customer's historical patterns:
        • High Risk (3x Average): If current order > 3× average order value:
          • Automatically cancels the order with reason “FRAUD”
          • Issues refund and restocks inventory
          • Updates order with "fraud-assessed" tag and cancellation note
        • Medium Risk (1.5x Average): If current order > 1.5× average order value:
          • Puts order on hold for manual review
          • Adds tags: “on-hold, manual-review, problem-customer”
          • Adds note requiring manual verification
      • Problem Customer Check - Queries the system for previous problem cases:
        • If customer has 2+ previous incidents, puts current order on hold regardless of amount
        • Uses the same hold process as medium-risk orders

Set up Action, xCache, Formula and Flow

Action

Set up a custom Action with a String Input parameter called JSONPayloadIn. The example below has an Output parameter JSONPayloadOut defined, however we do not use it in this example.  

xCache

To securely store the Shopify API key we use an xCache record. Only System Administrators or specifically authorized users will be able to access this value.

  • Open the North52 App
  • Navigate to Business Process Activities > N52 xCache
  • Create a new xCache record
    • Enter Shopify for the Category
    • Add AccessToken to the Base Key so that the full BaseKey name is Shopify_AccessToken
    • In the Value Information tab enter your Access Token into the Value (Secured) field
  • Click Save

We also store the GraphQL queries in xCache so that they can be reused in multiple formulas. These are:

Shopify_mutation_orderCancel

mutation orderCancel($orderId: ID!, $reason: OrderCancelReason!, $notifyCustomer: Boolean!, $refund: Boolean!, $restock: Boolean!) { orderCancel(orderId: $orderId, reason: $reason, notifyCustomer: $notifyCustomer, refund: $refund, restock: $restock) { job { id done } userErrors { field message } } }

Shopify_mutation_orderUpdate

mutation orderUpdate($input: OrderInput!) { orderUpdate(input: $input) { order { id tags note updatedAt } userErrors { field message } } }

Shopify_query_getCustomerOrders

query getCustomerOrders($customerId: ID!, $first: Int!) { customer(id: $customerId) { id displayName orders(first: $first) { edges { node { id totalPriceSet { shopMoney { amount currencyCode } } createdAt } } pageInfo { hasNextPage endCursor } } } }

Formula

Copy the following changing the relevant part to start defining the process of creating a new formula. 

  • Open the North52 App
  • Navigate to Business Process Activities > Formulas
  • Create a new formula, setting the following values in the Formula Guide:
    • Source Entity set to N52 Command
    • Set Formula Type to Action
    • Select the Decision Table editor
  • Change the Name of the formula to Shopify - Rules for Holding or Cancelling Orders
  • Select the Action Event, in our case n52demo_ShopifyWebook
  • Click Save
  • Edit/Create the follow Decision Table sheets:

Global Calculations Sheet

Set up variables to extract relevant information from the JSON payload.

Global Actions Sheet

Set up Global Actions that will be referenced in the Decision Tables.

CallShopifyAPI
CallRestAPI(
 SetRequestBaseURL('https://north52-demo-01.myshopify.com'),
 SetRequestResource('admin/api/2024-07/graphql.json'),
 SetRequestDetails('POST'),
 SetRequestHeaders('Content-Type', 'application/json', 'X-Shopify-Access-Token', xCacheGetGlobal('Shopify_AccessToken')),
 SetRequestParams('RawContentApplicationJSON',GetVar('Shopify API Payload')),
 SetRequestAuthenticationNone(),
 SetRequestFiles(), 
 SetRequestExpected('OK'),  
 SetRequestActionPass(GetVar('responsecontent')),
 SetRequestActionFail(GetVar('responsecontent'))
)
GetCustomerOrders
CreateJObject(
CreateJProperty('query', xCacheGetGlobal('Shopify_query_getCustomerOrders')),
CreateJProperty('variables',
CreateJObject(
CreateJProperty('customerId', 'gid://shopify/Customer/' + {0}),
CreateJProperty('first', 250)
)
)
)
CancelOrder
CreateJObject(
CreateJProperty('query', xCacheGetGlobal('Shopify_mutation_orderCancel')),
CreateJProperty('variables',
CreateJObject(
CreateJProperty('orderId','gid://shopify/Order/' + {0}),
CreateJProperty('reason', 'FRAUD'),
CreateJProperty('notifyCustomer', true),
CreateJProperty('refund', true),
CreateJProperty('restock', true)
)
)
)
CancelOrderUpdate
CreateJObject(
CreateJProperty('query', xCacheGetGlobal('Shopify_mutation_orderUpdate')),
CreateJProperty('variables',
CreateJObject(
CreateJProperty('input',
CreateJObject(
CreateJProperty('id', 'gid://shopify/Order/' + {0}),
CreateJProperty('tags', 'fraud-assessed'),
CreateJProperty('note', 'CANCELLED due to fraud assessment')
)
)
)
)
)
OrderOnHold
CreateJObject(
CreateJProperty('query', xCacheGetGlobal('Shopify_mutation_orderUpdate')),
CreateJProperty('variables',
CreateJObject(
CreateJProperty('input',
CreateJObject(
CreateJProperty('id', 'gid://shopify/Order/' + {0}),
CreateJProperty('tags', 'on-hold, manual-review, problem-customer'),
CreateJProperty('note', 'ORDER ON HOLD - Requires manual verification before fulfillment')
)
)
)
)
)

Global FetchXml Sheet

This query finds all the previous cases for the customer where the type is Problem.

Find Problem Cases for Customer
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
 <entity name="incident">
   <attribute name="incidentid" />
    <filter type="and">
     <condition attribute="casetypecode" operator="eq" value="2" />
   </filter>
   <link-entity name="contact" from="contactid" to="customerid" link-type="inner" alias="ab">
     <filter type="and">
       <condition attribute="n52demo_shopifycustomerid" operator="eq" value="{0}" />
     </filter>
   </link-entity>
 </entity>
</fetch>

Get Customer Orders Sheet

This sheet retrieves the customer orders from Shopify API.

Calculate Total Order Value Sheet

This sheet calculates the total order values based on the orders retrieved in the previous sheet.

Row 3 of the ForEachRecord column 

Calculate Average Order ValueSheet

This sheet calculates the average order value by dividing the total order value (from previous sheet) by the number of orders.

Potential Fraud Sheet

This sheet uses a multiple of the average order value from the previous sheet as a condition to determine potential fraud. If it is over the thresholds the order may be put on hold or cancelled.

Problem Customer Sheet

This sheet determines if the customer has had two or more previous ‘Problem’ cases, and if so puts the order on hold.

Details of condition in column B

Flow

The Flow acts as a webhook receiver and passes the body of the request to the custom action and ultimately on to the North52 Formula.

Shopify Webhook Setup

The Flow HTTP POST URL is used in the Shopify Webhook setup.

 

Testing

Problem Cases Example:

Result in Shopify: