F&O's workflow engine has three built-in ways to decide who approves a document. Most approval patterns fit one of them. The exceptions are where custom providers come in - scenarios like budget-aware routing, approvers that depend on live inventory, or approval chains that branch on data the workflow designer UI can't express.
Finance teams running purchase requisitions often describe this wish: "route approvals based on the department's current budget utilization. Under 70%, manager approval. 70-90%, finance controller. Over 90%, CFO." That decision has to happen at submission time with live data. The built-in providers can't do it.
Custom providers can.
The three provider types
F&O workflows use three extension points for "who approves this":
- Participant provider - returns a list of users that match a role or group. Good for "send to the AP clerks" or "any sales manager".
- Hierarchy provider - walks an organizational hierarchy (manager of the requestor, up 2 levels) based on positions and reporting relationships.
- Queue provider - routes to a work item queue that any authorized user can pick up.
Each one has configuration UI where workflow designers pick from available providers. If the provider you need doesn't exist, you write one.
When configuration isn't enough
Clear signals that built-in providers won't cut it:
- Approver depends on transaction-level data (amount, budget state, product category)
- Approver changes based on external factors (credit check, inventory availability)
- Approval chain has conditional branching the workflow designer can't express cleanly
- You need to query external systems during routing
If the business rule fits in decision-activity conditions, use those - simpler. Custom providers are for when the rule is "go find who approves this based on logic too complex for the UI".
A budget-aware participant provider
For the budget-based approval scenario, a participant provider is the right fit: each step returns "the user who should approve this, right now". The interface is WorkflowParticipantProvider:
The attribute registers the class as a participant provider so the workflow designer UI picks it up. resolve is called at runtime for each step - it gets the current transaction context and returns one or more users.
Registration
Two paths to make the provider available in the designer:
- Attribute-based discovery (F&O 2022+) - WorkflowParticipantProviderAttribute registers automatically. Restart the designer to pick it up.
- Manual registration via WorkflowParticipantTable - insert a row pointing to your class and category. Older builds still need this.
When a provider doesn't show in the dropdown: class compiles, attribute correct, workflow document type matches, designer session restarted. One of those is usually wrong.
Testing that earns its keep
Workflow debugging is painful without a testing discipline. A pattern that works:
- Unit test the resolve logic - isolate calculateBudgetUtilization and the approver-lookup helpers. SysTest-based unit tests, no workflow runtime needed.
- Integration test the provider - instantiate MyBudgetApproverProvider, construct a mock WorkflowContext, call resolve, assert the returned users.
- End-to-end test in UAT - submit an actual workflow, verify routing, verify notifications, verify the audit trail.
Without step 1 and 2, every bug becomes an end-to-end debug session - hours per iteration. With them, 90% of logic errors surface before the workflow ever runs.
Line-item providers
Purchase requisitions and similar documents have lines. Each line can need its own approval based on category or amount. Line-item providers operate per-line, returning approver assignments per line and aggregating them into the workflow's step.
The interface is WorkflowLineItemProvider. Same pattern as participant provider but scoped to a line type (e.g., PurchReqLine).
A common use case: different product categories need different buyers to approve. Office supplies → facilities buyer. IT equipment → IT procurement. The line-item provider dispatches each line to the right person.
When custom is too far
If your provider queries three external systems, branches five ways, and resolves 15 approvers, the business rule is probably more complex than an F&O workflow should carry. Alternatives:
- Power Automate flows triggered by a custom service, owning routing externally
- Azure Logic Apps with decision blocks, writing back to F&O via data entities
- A bespoke approval module built alongside F&O rather than inside the workflow engine
Custom providers sit in the middle: in-process X++ logic past what configuration can express, but short of full external orchestration. Pick them when you need that in-process speed and consistency.
What a budget-aware provider ships as
A working custom provider has: the class implementing the interface, a SysTest suite covering the lookup logic, a test workflow in UAT that exercises the happy path and the edge cases, and a deployment runbook. The cost is a few days for the first one. After that, reuses of the pattern are half a day each.