Skip to content

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

Headline "How decision graphs decide" beside an illustration of a decision graph splitting into approve and decline, on a vivid purple gradient.

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:

  1. Gathers the data: the verification result, the customer's entity and linked identity, any screening results, and the Device Intelligence signals.

  2. Walks the graph from the start node, evaluating each branch and executing each action.

  3. Lands on a terminal status node, which sets the outcome.

  4. Records the path it took, the trace, and sends the workflow.run.completed webhook.

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 true or false edge.

Action

A side effect: tag the run, send a workflow.action webhook, or open a case for an investigator. Actions never stop the flow.

Wait

Holds the run until AML screening, or a business's key people, resolve, up to a timeout.

Status

Terminal. Sets the outcome to approve, decline or review.

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 as status, reasonCode, assuranceLevel (chip, gov_db or document), facialMatch, facialConfidence, facialMatchSource, age and documentExpired.

  • entity.* and identity.*: 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.* and ip.*: Device Intelligence, such as how many other people used the same device and whether the IP belongs to a datacentre.

  • email.* and phone.*: contact verification results.

  • business.* and keyPeople.*: 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

approve

APPROVED

decline

REJECTED

review

UNDER_REVIEW

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:

  1. Wait for screening to resolve, up to a timeout.

  2. If screening.confirmed is true, decline.

  3. If screening.anyMatch is true, open a case, then review.

  4. If verification.status is not VERIFIED, decline.

  5. If device.matchedEntities is 2 or more, review.

  6. If verification.facialMatchSource is document, review.

  7. If verification.assuranceLevel is in chip or gov_db, approve.

  8. 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

VERIFIED, gov_db, no match

7

approve

B: passport, possible PEP match on screen

anyMatch true

3

case opened, review

C: NIN, selfie mismatch

FAILED, 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

  1. Write the policy in plain sentences before drawing anything, including the default outcome.

  2. Put hard stops (confirmed watchlist matches) first and approvals last.

  3. Decide, for each check failure, whether it declines or goes to review, and write that down as a rule.

  4. Use exists wherever a missing value should mean something.

  5. Open a case on the paths that need an investigator, not only a review.

  6. Test each path in sandbox with the published test IDs before publishing to production.

  7. Store the workflowVersion with each outcome, so you can later show which rules a customer went through.

Sources

Charles Archibong

About the author

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.

  • Headline "Not every pass is equal" beside an illustration of three rising tiers, on a vivid purple gradient.

    Product Updates

    Not every pass is equal: using assurance levels in onboarding decisions

    A chip pass, a government database pass and a document-only pass are different strengths of evidence. Decide in advance what each tier may do, route on the tier together with the photo the face was matched against, and let customers move up a tier rather than failing them.

  • Headline "Change flows without a release" beside an illustration of a continuous circular arrow, on a vivid purple gradient.

    Product Updates

    Changing a verification flow without shipping an app release

    Mount the SDK with a workflow ID and the flow's configuration is fetched from the server on each verification. Re-publishing changes the steps, checks, copy and decision rules for the next verification, with no app release.

  • Headline "Face-match thresholds" beside an illustration of a face outline mapped with landmark points, on a soft lavender gradient.

    Identity Verification

    Setting a face-match threshold without guessing

    A face-match threshold is a policy choice between wrongly accepting impostors and wrongly rejecting real customers. Set the pass mark from labelled pairs of your own traffic, add a bounded review band just below it, and revisit both as your users and cameras change.

Build your product.We'll handle the rest.

Identity and compliance, end to end, built to global standards, priced for founders.

How decision graphs decide approve, review or decline · Myaza Trust