Integration: Custom Workflow Behavior
Overview
ID Dataweb workflows are configurable — you can add steps, remove steps, and attach additional checkers to any step. For Gateway integrations, customization is largely transparent to your application. For API integrations, adding or changing steps means your application needs to handle the new interactions.
This page covers what changes (and what doesn't) when you customize a workflow.
Gateway (OIDC): Nothing Changes
Gateway integrations are based on OpenID Connect. Your application sends an /authorize request and receives an authorization code after the user completes the flow. The hosted UI handles all step sequencing — your application is not involved in the step-by-step logic.
When you add or change a step in a Gateway workflow:
- The user sees the additional interaction in the hosted UI
- Your application sends the same
/authorizerequest, unchanged - Your application receives the same authorization code and performs the same token exchange
The response will reflect what actually ran — including any additional steps. You do not need to change your backend code to handle a new step.
The only thing to plan for on the Gateway side is the user experience: adding a document capture step, for example, means users will complete a mobile document capture flow that wasn't there before. No code changes required, but worth communicating to users.
API: Handle Steps Dynamically with forwardApiKey
forwardApiKeyAPI integrations require your application to call each step explicitly. When you add a step to a workflow, your application needs to handle it.
How step chaining works
Every /slverify response includes a policyDecision field:
policyDecision | Meaning | What your app does next |
|---|---|---|
obligation | Step passed — another step is required | Call the next step using forwardApiKey from this response |
approve | Workflow complete — user verified | Grant access |
deny | Workflow complete — user not verified | Decline or route to fallback |
When policyDecision = obligation, the response includes forwardApiKey — the API key for the next step. Pass it as apikey in the next /slverify call.
Hardcoded step sequence
For a fixed workflow where you know the sequence in advance, call steps in order:
// Step 1 — Session Risk
const step1 = await slverify(SESSION_RISK_KEY, { country: 'US' });
if (step1.policyDecision === 'deny') return deny();
// Step 2 — PII Validation (key comes from step 1 forwardApiKey)
const step2 = await slverify(step1.forwardApiKey, piiAttributes);
if (step2.policyDecision === 'deny') return deny();
// Step 3 — SMS Link (key comes from step 2 forwardApiKey)
const step3 = await slverify(step2.forwardApiKey, fastTapAttributes);
return step3.policyDecision === 'approve' ? approve() : deny();This is straightforward when the workflow is fixed and you control the step sequence.
Dynamic step sequence
When you add steps, support multiple workflow configurations, or want your integration to handle workflow changes without code deploys, drive the flow from policyDecision and forwardApiKey rather than hardcoding the step order:
async function runWorkflow(initialKey, initialAttributes) {
let apiKey = initialKey;
let attributes = initialAttributes;
while (true) {
const res = await slverify(apiKey, attributes);
if (res.policyDecision === 'approve') return { result: 'approve', data: res };
if (res.policyDecision === 'deny') return { result: 'deny', data: res };
// obligation — another step required
apiKey = res.forwardApiKey;
attributes = await collectAttributesForNextStep(apiKey);
// collectAttributesForNextStep presents the appropriate UI for the next step
// and returns the user's input as userAttributes
}
}With this pattern, adding a step to the workflow in the Admin Console does not require a code change — your application handles the new step automatically, as long as it knows how to collect input for that step type.
What to handle when adding a step
New user input. Each step type requires specific userAttributes. Adding a Government ID and Selfie Match step requires calling /async-ui/send-link and handling the capture redirect. Adding a Dynamic KBA step requires displaying the questions and submitting answers. Plan the UI and input handling for any new step type before deploying.
New deny points. Each step is a point where policyDecision = deny can be returned. Confirm that your application handles deny at any point in the chain, not just at the final step.
No change to approval. policyDecision = approve means the full workflow has passed — the same regardless of how many steps ran to get there.
Session continuity across steps
Link all steps of a user session using the asi (Application Session Identifier). Pass the transaction_id returned by the first /slverify call as asi in all subsequent calls for that session. This is required for accurate reporting in the Admin Console and is important for debugging.
// First call — save transaction_id
const step1 = await slverify(SESSION_RISK_KEY, attrs);
const asi = step1.transaction_id;
// All subsequent calls — include asi
const step2 = await slverify(step1.forwardApiKey, step2Attrs, { asi });
const step3 = await slverify(step2.forwardApiKey, step3Attrs, { asi });See ID Dataweb API for full session tracking documentation.
Related Resources
→ Customizing Workflows | → ID Dataweb API | → API Authentication | → Interpreting Results — API | → Gateway (OIDC) Integration
Updated 2 days ago
