How decision graphs turn checks into approve, review or decline
When a verification finishes, the workflow's decision graph gathers the results, walks branches over a closed set of fields, and lands on approve, review or decline. The outcome sets the customer's disposition without rewriting what the checks found.

Charles Archibong, Co-founder
· 6 min read

Key takeaways
- Checks report facts; the decision graph turns those facts into approve, review or decline.
- An outcome sets the customer's disposition but never changes the verification's own result.
- Fields fail closed: a missing value makes a comparison false, so test presence with exists.
- Each run is pinned to the workflow version it started with, so re-publishing never changes a decision in flight.
A workflow decides an outcome in two stages. First the checks run and report facts: the document was read, the government record matched, the selfie scored 71 against the record photo, the watchlist screen found a possible match. Then the workflow's decision graph reads those facts, follows the branches you drew, and lands on approve, review or decline. The checks never decide whether someone is onboarded; the graph does.
Keeping those stages apart is the useful part. The facts stay fixed and auditable, and the policy that interprets them lives in one place you can change by re-publishing. This article explains how a run works in Myaza Trust Workflows and how to design a graph that sends the right cases to a person.
What happens when a verification finishes
When a verification reaches a terminal state, the engine starts a run for it. According to the decisioning documentation, a run does four things:
Gathers the data: the verification result, the customer's entity and linked identity, any screening results, and the Device Intelligence signals.
Walks the graph from the start node, evaluating each branch and executing each action.
Lands on a terminal status node, which sets the outcome.
Records the path it took, the trace, and sends the
workflow.run.completedwebhook.
There is one run per verification, and runs are idempotent, so a verification that is retried or re-processed is never decided twice.
The four kinds of node
Node | What it does |
|---|---|
Branch | Evaluates a condition and follows its |
Action | A side effect: tag the run, send a |
Wait | Holds the run until AML screening, or a business's key people, resolve, up to a timeout. |
Status | Terminal. Sets the outcome to |
You can build the graph as a simple ordered rule list or on an advanced canvas. The rule list suits most onboarding policies, which are a sequence of "if this, then that outcome" statements with a default at the end.
What a branch can read
Conditions read a closed namespace of fields, grouped by where the fact comes from:
verification.*: the check result, such asstatus,reasonCode,assuranceLevel(chip,gov_dbordocument),facialMatch,facialConfidence,facialMatchSource,ageanddocumentExpired.entity.*andidentity.*: the customer's risk tier and disposition, and the linked identity's trust state.screening.*: whether any watchlist screen matched, whether a match is confirmed, the status of each screen type, and the highest match score.device.*andip.*: Device Intelligence, such as how many other people used the same device and whether the IP belongs to a datacentre.email.*andphone.*: contact verification results.business.*andkeyPeople.*: business verification and due diligence on its key people.questionnaire.<key>: answers to any questionnaire in the flow.
Operators are eq, neq, gt, gte, lt, lte, in, nin, contains and exists, combined with all, any and not.
Two rules shape how you write conditions. First, a field that does not exist in the namespace is rejected when you publish, so a typo surfaces at once rather than as a rule that silently never matches. Second, a null value fails the comparison closed. If a verification carries no facial confidence because no comparison ran, verification.facialConfidence gte 80 is false, not true. When absence matters, test for it explicitly with exists.
What an outcome changes, and what it does not
A status node sets the entity's disposition, the compliance decision about the person or business:
Outcome | Entity disposition |
|---|---|
|
|
|
|
|
|
It never overrides the verification's own result. A verification whose checks failed stays failed in checkStatus even if your graph approves it, and the top-line status records the approval. That is how an auditor can later see both the exception and the fact it overrode.
Your backend hears the outcome on workflow.run.completed, and on verification.status_updated with source: "workflow" whenever the verdict moves the verification's status. What you do with it, such as granting access or holding an account, is your code's decision.
A worked graph for a consumer lender
Consider a hypothetical lender onboarding individuals in Nigeria with a workflow that runs AML screening. Its policy, written as an ordered rule list, might read:
Wait for screening to resolve, up to a timeout.
If
screening.confirmedis true, decline.If
screening.anyMatchis true, open a case, then review.If
verification.statusis notVERIFIED, decline.If
device.matchedEntitiesis 2 or more, review.If
verification.facialMatchSourceisdocument, review.If
verification.assuranceLevelis inchiporgov_db, approve.Otherwise, review.
The order carries the policy. Screening comes first because a confirmed watchlist match should decline someone whose documents are perfect. The device rule sits before approval because a handset used by several other applicants is worth a look however clean the individual check. Rule 6 exists because a selfie matched only to the photo printed on a document is weaker evidence than a match against the government record or a verified chip photo.
Now run three applicants through it:
Applicant | Facts | Rule that decides | Outcome |
|---|---|---|---|
A: BVN, clean screen, record photo matched |
| 7 | approve |
B: passport, possible PEP match on screen |
| 3 | case opened, review |
C: NIN, selfie mismatch |
| 4 | decline |
Applicant C shows why the graph reads facts rather than replacing them. If your policy instead sends selfie mismatches to review, change rule 4 to route verification.reasonCode eq selfie_mismatch to review before a general decline. A reviewer who then approves after looking at the photos produces a verification that is approved with checkStatus: "failed", and both statements are true.
Myaza Trust ships templates, such as KYC plus AML screening and risk-tiered onboarding, that start with a decision graph already drawn. They are a reasonable first draft, not a policy you should publish without reading.
Behaviour worth knowing before you publish
Runs are pinned. A run uses the workflow version and graph snapshot it started with. Re-publishing a stricter graph does not change a decision already in flight, which matters when a run is waiting days on a business's directors.
Screening waits for the first answer only. A screening wait holds until the first resolution. Later re-screens are handled by ongoing monitoring, not by re-deciding the onboarding.
People outrank the graph. A reviewer's decision wins over the workflow's. If someone on your team decides while the run is still waiting, their decision stands, and the workflow's later verdict does not move the status.
Engine faults are not declines. workflow.run.failed means the engine could not finish a run. Treat it as an incident to investigate, never as a rejection of the customer.
Actions are side effects. Opening a case or sending a webhook does not end the run. The graph continues until it reaches a status node, so make sure every path does.
A checklist for your first graph
Write the policy in plain sentences before drawing anything, including the default outcome.
Put hard stops (confirmed watchlist matches) first and approvals last.
Decide, for each check failure, whether it declines or goes to review, and write that down as a rule.
Use
existswherever a missing value should mean something.Open a case on the paths that need an investigator, not only a review.
Test each path in sandbox with the published test IDs before publishing to production.
Store the
workflowVersionwith each outcome, so you can later show which rules a customer went through.
Sources

Charles Archibong
Co-founder
Charles Archibong co-founded Myaza Trust. He writes about identity verification, financial technology, and the practical work of building trusted digital services.


