KentaGrams: Design Approaches To Zuora Workflow
Hi! My name is Kenta Tomura and I am a Senior Customer Strategist at Zuora. This is the first edition of “KentaGrams”, a Zuora Community series where I share best practices, including but not limited to:
- Configuring Zuora
- Integrating to Zuora
- Operationalizing around Zuora
- Your business journey through Zuora
Having worked with customers of all sizes across different verticals (B2Any SaaS, IoT, Enterprise SaaS, Automotive, OTT Media, etc, etc, etc), I have accumulated a lot of lessons learned (and scar tissue) over what to do, and just as important, what not to do.
In this edition of KentaGrams, I discuss typical design approaches to solve business use cases using Zuora Workflow.
Having designed and built countless workflows, I can categorize my approaches into two buckets:
- Batch Processing: Many at a time per execution
- Stream Processing: One at a time per execution
I tend to evaluate each use case in terms of which approach makes more sense, and then design necessary steps to optimize the flow. I usually define the end state first and then work backwards to determine what data I need, in what format, and how I would go about pulling the data together. Let's dive into each approach in more detail.
The basic premise of batch processing consists of:
- Getting a dump of data that fits business criteria
- Performing a set of actions for each data
- Give me a dump of past due invoices
- For each invoice:
- Evaluate the invoice amount
- If above a certain amount, flag for review and approval before writing it off
- If below a certain amount, write-if off (no review necessary)
Batch processing is suitable for working with larger volumes of data.
Step 1: Decide how you want to dump the data
What initial data to dump and how often is the most critical step; you not only want as much data one piece but in the right format.
- Data Source Export
- In Zuora Billing, each Data Source consists of pre-joined tables that represent a body of business data. For example, the Invoice Item Data Source looks like this:
- As long as the data I want is available across the objects in a given Data Source, Data Source Export tends to be my first option since it saves me from having to write SQL queries
- Data Query
- Data Query is more flexible and more powerful, provided you are comfortable with SQL and know your way around the Zuora Billing data model
- I lean on Data Query if I need to structure the data in ways that go beyond available Data Sources
- Other ways to get your starting data include
Step 2: Iterate (i.e. how do you want to loop the data?)
Once we get the initial data, we need to decide how we want to loop through it - do you want to go row by row? Or skip based on a unique Id?
- For example, I may do something like...
- Export Rate Plan Charge Data Source
- Iterate by Subscription Name (aka Subscription Number) → Workflow will skip Rate Plan Charge records to get to the next Rate Plan Charge record with a unique Subscription Name/Number value
- Bulking is also an option; instead of working one Rate Plan Charge at a time, you can bulk to process, say, 50 Rate Plan Charges at a time; this is useful if you want to update a field value (rather than one at a time)
- Iteration is not necessary if you simply need to move the data from Step 1 to a destination as-is. For example, you might extract data, and move the file to an SFTP location
Step 3: Define what needs to happen within each iteration
Each iteration gets its own branch, from which we can define a set of actions to take place
- Forking: If this, then that (e.g. is the invoice is over or between a certain amount?)
- If/Then Task
- Case Task
- Enriching the data: In case the data dump doesn’t include everything you need
- Query Task: Provides an easy way to establish a one-to-many relationship of data to process multiple "child" records (e.g. Account and Subscriptions)
- GET API Callout Task: Saves you from using multiple Query Tasks if you know your Zuora REST APIs well
- Transforming: In case the structure or the format of the data needs tweaking
- Liquid Task:
- Liquid is a lightweight template language
- Virtually all Zuora Workflow Tasks supports Liquid
- JSONata Task:
- JSONata is a flexible query language
- It is tailormade for handling complex JSON data
- End State Action (i.e. what ultimately needs to happen)
Here, a Workflow is triggered using a specific data point per run. Each run may execute quicker, but each ping is treated as a separate request that may sit in a queue. For example:
- Zuora Notification triggers a Workflow via callout; the payload includes:
- Account Id
- Declined Payment Id
- From here, the Workflow enriches the initial payload with other data
- Associated masked Payment Method data
- Associated Subscription
- And send perform an action, such as sending a personalized email to a customer
Keep in mind Zuora Workflow is designed as an asynchronous tool; the response you receive upon triggering a workflow won't be the result of the whole process, but rather whether the request successfully queued.
Step 1: Trigger a Workflow with a defined set of input from a source
- Another Workflow
- Zuora Notification Callout
- An API ping from an external system
- Manual (with or without input parameters specified)
Step 2: Define what needs to happen within each iteration
- If/Then Task
- Case Task
- Enrich and transform the data: As the starting payload tend to be lightweight, you might find more need to enrich and transform the data
- End State Action (i.e. what do you need the process to ultimately do)
If you have questions or would like to share your experience, feel free to reply to this post! I'm also taking requests for future KentaGrams. Lastly, I'm plugging @Serg's great article on best practices when building WF.
Senior Customer Strategist, Customer Primacy
P.S. Does anyone else keep a collection of go-to Liquid syntaxes?