{"id":33329,"date":"2022-12-12T14:57:04","date_gmt":"2022-12-12T09:27:04","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=33329"},"modified":"2026-02-10T14:17:42","modified_gmt":"2026-02-10T08:47:42","slug":"get-business-process-flow-stages-in-a-defined-sequence-within-microsoft-dynamics-365-crm","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2022\/12\/get-business-process-flow-stages-in-a-defined-sequence-within-microsoft-dynamics-365-crm\/","title":{"rendered":"Get Business Process Flow Stages in a defined sequence within Microsoft Dynamics 365 CRM"},"content":{"rendered":"<p>If you\u2019ve ever tried to retrieve Business Process Flow (BPF) stages programmatically in Dynamics 365 CRM, you\u2019ve probably noticed something frustrating: the order you get from the backend doesn\u2019t always match what you see on the form.<\/p>\n<p>Recently, while working on a real project requirement, you may find yourself needing the BPF stages in the exact sequence shown to users on the entity record. Naturally, your first instinct would be to query the processstage table. However, once you do that, you\u2019ll quickly realize that the stages are not returned in the same order as the UI.<\/p>\n<p>In this blog, you\u2019ll learn how you can reliably retrieve Business Process Flow stages in their defined sequence by using the Processes (workflow) table and the clientdata attribute, without compromising on technical accuracy or flexibility.<\/p>\n<p><strong>What Is a Business Process Flow in Dynamics 365 CRM?<\/strong><\/p>\n<p>A Business Process Flow in Dynamics 365 CRM is designed to guide users through a structured sequence of stages, such as qualifying a lead or closing an opportunity, directly on the entity form. Each stage follows a predefined order that users rely on for day-to-day operations.<\/p>\n<p>The challenge you face as a developer is that this UI-defined order is not always preserved when you query Dataverse tables directly.<\/p>\n<p><strong>Scenario: When Your Custom BPF Stage Appears Out of Order<\/strong><\/p>\n<p>As part of your requirement, you add a custom stage called <em>Verification<\/em> right after the <em>Qualify<\/em> stage in the out-of-the-box leadtoopportunitysalesprocess Business Process Flow.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-33335\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow.png\" alt=\"\" width=\"1352\" height=\"531\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow.png 1352w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow-300x118.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow-1024x402.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow-768x302.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/1Business-Process-Flow-660x259.png 660w\" sizes=\"(max-width: 1352px) 100vw, 1352px\" \/><\/p>\n<p>Your expectation is simple: when you retrieve the stages programmatically, they should appear in the same order, Qualify first, Verification next, followed by the remaining stages.<\/p>\n<p>Why Querying the processstage Table Doesn\u2019t Work for Stage Order<\/p>\n<p>When you query the processstage table using an OData query, you\u2019ll notice that the custom Verification stage appears at the end, rather than immediately after Qualify.<\/p>\n<p>Even if you try ordering the result using versionnumber, the sequence still doesn\u2019t align with what you see on the form.<\/p>\n<p><strong>Query:<\/strong><\/p>\n[OrganizationURI]\/data\/v9.0\/processstages?$filter=_processid_value=\u201927919E14D1-6489-4852-ABD0-A63A6ECAAC5D\u2019&amp;$select=stagename&amp;$orderby=versionnumber<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-33334\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/2Business-Process-Flow.jpeg\" alt=\"Business Process Flows\" width=\"823\" height=\"596\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/2Business-Process-Flow.jpeg 823w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/2Business-Process-Flow-300x217.jpeg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/2Business-Process-Flow-768x556.jpeg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/2Business-Process-Flow-660x478.jpeg 660w\" sizes=\"(max-width: 823px) 100vw, 823px\" \/><\/p>\n<p>This clearly shows a platform behavior you need to be aware of: the processstage table does not guarantee the UI-defined order of Business Process Flow stages.<\/p>\n<p><strong>Solution: Use the Processes (Workflow) Table<\/strong><\/p>\n<p>At this point, you need a more reliable source of truth.<\/p>\n<p>When you look deeper into Dynamics 365 CRM internals, you\u2019ll find that the Processes (workflow) table stores not only workflows, but also Business Process Flows, actions, and dialogs. More importantly, it includes the clientdata attribute, which preserves the actual stage sequence.<\/p>\n<p>This is where the solution starts to come together.<\/p>\n<p><strong>Note:<\/strong>\u00a0To get the stages of their desired Business Process Flow, one must know the GUID of their respective Business Process Flow to apply the filer on.<\/p>\n<p><strong>Fetching the BPF Definition Using FetchXML<\/strong><\/p>\n<p>To retrieve the correct stage order, you query the Processes table using the unique GUID of your Business Process Flow.<\/p>\n<p><strong>Note:<\/strong> You must know the GUID of the specific BPF you\u2019re targeting.<\/p>\n<pre class=\"lang:css gutter:true start:1\">&lt;fetch&gt;\r\n\r\n&lt;entity name=\"workflow\"&gt;\r\n\r\n&lt;attribute name=\"clientdata\"\/&gt;\r\n\r\n&lt;filter&gt;\r\n\r\n&lt;condition attribute=\"workflowid \" operator=\"eq\" value=\"919e14d1-6489-4852-abd0-a63a6ecaac5d\"\/&gt;\r\n\r\n&lt;\/filter&gt;\r\n\r\n&lt;\/entity&gt;\r\n\r\n&lt;\/fetch&gt;<\/pre>\n<p><strong>Understanding What the clientdata Attribute Contains<\/strong><\/p>\n<p>The <strong>clientdata<\/strong> field is a JSON string that holds the complete definition of the Business Process Flow, including the exact order of its stages.<\/p>\n<p>To deserialize this JSON, you can use the following class structure:<\/p>\n<pre class=\"lang:css gutter:true start:1\">public class List\r\n\r\n{\r\n\r\npublic string description { get; set; }\r\n\r\npublic Steps steps { get; set; }\r\n\r\npublic string stageId { get; set; }\r\n\r\npublic string nextStageId { get; set; }\r\n\r\n}\r\n\r\npublic class Stepsdata\r\n\r\n{\r\n\r\npublic Steps steps { get; set; }\r\n\r\n}\r\n\r\npublic class StepLabels\r\n\r\n{\r\n\r\npublic List&lt;object&gt; list { get; set; }\r\n\r\n}\r\n\r\npublic class Steps\r\n\r\n{\r\n\r\npublic List&lt;List&gt; list { get; set; }\r\n\r\n}<\/pre>\n<p><strong>How You Can Identify the Correct Stage Sequence<\/strong><\/p>\n<p>Once you deserialize the JSON, you\u2019ll see a nested structure where the steps array preserves the exact sequence of BPF stages.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-33333\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/3Business-Process-Flow.jpeg\" alt=\"\" width=\"944\" height=\"385\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/3Business-Process-Flow.jpeg 944w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/3Business-Process-Flow-300x122.jpeg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/3Business-Process-Flow-768x313.jpeg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/3Business-Process-Flow-660x269.jpeg 660w\" sizes=\"(max-width: 944px) 100vw, 944px\" \/><\/p>\n<p><strong>Here\u2019s what you\u2019ll notice:<\/strong><\/p>\n<ul>\n<li>Position <strong>1<\/strong> contains the <strong>Qualify<\/strong> stage<\/li>\n<li>Position <strong>2<\/strong> contains your custom <strong>Verification<\/strong> stage<\/li>\n<li>Position <strong>0<\/strong> does not contain usable stage data<\/li>\n<\/ul>\n<p>Each stage also includes a nested steps node that stores additional metadata, such as the stage description.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-33332\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow.jpeg\" alt=\"\" width=\"1179\" height=\"400\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow.jpeg 1179w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow-300x102.jpeg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow-1024x347.jpeg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow-768x261.jpeg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/4Business-Process-Flow-660x224.jpeg 660w\" sizes=\"(max-width: 1179px) 100vw, 1179px\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-33331\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow.png\" alt=\"\" width=\"1177\" height=\"467\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow.png 1177w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow-300x119.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow-1024x406.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow-768x305.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/12\/5Business-Process-Flow-660x262.png 660w\" sizes=\"(max-width: 1177px) 100vw, 1177px\" \/><\/p>\n<p>In the below code, we have used nested\u00a0foreach\u00a0to segregate the JSON formatted data and loop through the parent and child steps capturing the required details from the respective Business Process Flow stages.<\/p>\n<p>In the code, we have printed the\u00a0description\u00a0value which is the stage name in a trace, but you can definitely go ahead further and use these details as per your business use case.<\/p>\n<pre class=\"lang:css gutter:true start:1\">public void sequenceBPFStages(IOrganizationService service, ITracingService trace)\r\n\r\n{\r\n\r\nList&lt;StepLabels&gt; convertJson = new List&lt;StepLabels&gt;();\r\n\r\nconvertJson = clientData.Deserialize&lt;StepLabels&gt;();\r\n\r\n\u00a0\r\n\r\n\/\/Here we will get the BPF stages inside list of steps, so below we have added \/\/foreach loop of steps inside for loop of list of steps\r\n\r\n\u00a0\r\n\r\nfor (int i = 0; i &lt; convertJson.steps.list.Count; i++)\r\n\r\n{\r\n\r\n\/\/Check if no steps present then do not go inside loop\r\n\r\n\u00a0\r\n\r\nif (convertJson.steps.list.Count &gt; 0)\r\n\r\n{\r\n\r\nforeach (var item in convertJson.steps.list[i].steps.list)\r\n\r\n{\r\n\r\n\/\/Name of Bpf stage \u2013 in json we will get description \/\/field which is Name of BPF stage\r\n\r\nString bpfStagesName = item.description != \"\" ? item.description : string.Empty;\r\n\r\ntrace.Trace(\"Bpf Stages name\" + bpfStagesName);\r\n\r\n\u00a0\r\n\r\n\u00a0\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n\r\n}<\/pre>\n<p>In this example, you\u2019re simply tracing the stage names, but you can easily extend this logic to support validations, reporting, or downstream business rules based on stage sequence.<\/p>\n<p><strong>Frequently Asked Questions<\/strong><\/p>\n<p><strong>Why are you not getting BPF stages in the correct order from processstage?<\/strong><\/p>\n<p>Because the processstage table does not store the UI-defined sequence of stages. Sorting by attributes like versionnumber does not guarantee the correct order.<\/p>\n<p><strong>Where does Dynamics 365 actually store the BPF stage order?<\/strong><\/p>\n<p>The correct sequence is stored in the clientdata attribute of the Processes (workflow) table.<\/p>\n<p><strong>Will this work for custom stages you add later?<\/strong><\/p>\n<p>Yes. Any custom stages you add are reflected in the clientdata JSON in the exact order defined in the BPF designer.<\/p>\n<p><strong>Conclusion<\/strong><\/p>\n<p>If you need Business Process Flow stages in the same order users see on the form, querying the processstage table won\u2019t be enough.<\/p>\n<p>By retrieving and deserializing the clientdata field from the Processes (workflow) table, you can confidently work with BPF stages in their defined sequence, making your Dynamics 365 CRM customizations more accurate, predictable, and reliable.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you\u2019ve ever tried to retrieve Business Process Flow (BPF) stages programmatically in Dynamics 365 CRM, you\u2019ve probably noticed something frustrating: the order you get from the backend doesn\u2019t always match what you see on the form. Recently, while working on a real project requirement, you may find yourself needing the BPF stages in the\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2022\/12\/get-business-process-flow-stages-in-a-defined-sequence-within-microsoft-dynamics-365-crm\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":11,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[6,18,2361],"tags":[228],"class_list":["post-33329","post","type-post","status-publish","format-standard","hentry","category-business-process-flows","category-dynamics-365-v9-2","category-technical","tag-business-process-flow-dynamics-crm"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/33329","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=33329"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/33329\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=33329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=33329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=33329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}