Skip to main content

Get a customer's reports and a lending decision

Turn a customer's classified transactions into reports and a lending decision: a proceed, conditional or blocked verdict, with any computed limits.

Before you start​

  • An API key with these scopes (see Authentication): customer:riskscore to refresh reports, customer:reports to read them, and decision-policies:read and decision-policies:evaluate for decision policies. The Node.js, Python and C# snippets read the key from the WSD_API_KEY environment variable.
  • The sandbox base URL: https://sandbox.walkerstdata.com.au.
  • A customer with enriched transactions (see Classify a customer's transactions or Upload PDF bank statements).
  • At least one decision policy set up for your client. Decision policies are enabled per client: if the decision policy endpoints return 404, contact us.
  • Node.js snippets use the built-in fetch (Node 18+) and top-level await, so save them as an .mjs file. Python snippets use requests. C# snippets are .NET 8 top-level programs using HttpClient and System.Text.Json, with no extra packages.

1. Refresh the reports​

Reports aren't computed automatically when transactions arrive. Once the customer's submission jobs have finished, start a refresh to compute the reports over all of the customer's enriched transactions. It returns 202 Accepted with a job to track. Start another refresh whenever you submit more transactions and want the reports to include them.

curl -X POST "https://sandbox.walkerstdata.com.au/v1/customer/524ba9bc-06e7-417e-bd54-b99785f5194a/reports/refresh" \
-H "x-api-key: YOUR_API_KEY"
{
"data": {
"jobId": "6b1c2d3e-4f50-6178-9abc-def012345678",
"flow": "ReportRefresh"
},
"message": null
}

A 409 means a job is already running for this customer: wait for it to finish, then try again. A 422 means the customer has no enriched transactions to report on yet.

2. Wait for the refresh to finish​

Poll the refresh job until it reaches Completed, CompletedWithErrors or Failed. Report refresh jobs don't send a job.completed webhook, so polling is the way to track them.

curl "https://sandbox.walkerstdata.com.au/v1/jobs/6b1c2d3e-4f50-6178-9abc-def012345678/status" \
-H "x-api-key: YOUR_API_KEY"

3. Read the report bundle​

One call returns all three reports: completeness, risk and aggregate. Check each report's status before reading its data:

statusMeaningdata?
pendingNot computed yetNo (null)
readyReflects all of the customer's transactionsYes
staleNew transactions have arrived since it was computed, or its latest refresh failedYes (last good)

failed: true means the most recent compute attempt errored; any data returned is the last good report.

curl "https://sandbox.walkerstdata.com.au/v1/customer/524ba9bc-06e7-417e-bd54-b99785f5194a/reports" \
-H "x-api-key: YOUR_API_KEY"
{
"data": {
"completeness": {
"status": "ready",
"failed": false,
"generatedAt": "2026-09-25T02:18:07Z",
"data": {
"summary": {
"completenessScore": 0.85,
"completenessTier": "high",
"totalMissingness": 0.15
}
}
},
"risk": {
"status": "ready",
"failed": false,
"generatedAt": "2026-09-25T02:18:07Z",
"data": {
"value": 9.54,
"rating": "B",
"pdConfidenceScore": 0.85,
"pdConfidenceRating": "High",
"errorCodes": []
}
},
"aggregate": {
"status": "stale",
"failed": true,
"generatedAt": "2026-09-18T01:02:44Z",
"data": {
"tables": [
{
"id": "income",
"name": "Income",
"hierarchy": "table",
"type": "objectArray",
"values": []
}
]
}
}
},
"message": null
}

Here completeness and risk are current, while the aggregate report's last refresh failed and the previous report is returned. See Completeness, Risk Score and Aggregate for every field.

4. Find the decision policy and its inputs​

List your decision policies to get the slug of the one you want and its declaredInputs. Every declared input must be supplied when you evaluate, with a value of the declared kind (string, decimal or boolean).

curl "https://sandbox.walkerstdata.com.au/v1/decision-policies?page=1&pageSize=20" \
-H "x-api-key: YOUR_API_KEY"
{
"data": {
"items": [
{
"policyId": "b91c4e27-6d3f-4a85-9e12-7f0a5c8d3b61",
"name": "Business line of credit v1",
"slug": "business-line-of-credit-v1",
"notes": "Three times average monthly net inflow, blocked on recent dishonours.",
"declaredInputs": [{ "name": "requested_amount", "kind": "decimal" }],
"defaultOutcome": "proceed",
"isArchived": false
}
],
"page": 1,
"pageSize": 20,
"totalCount": 1
},
"message": null
}

Each policy also carries its steps (applied in order; the first step that matches decides the outcome), its limits and the metrics and products they refer to. Archived policies are left out unless you pass includeArchived=true.

5. Evaluate the policy​

Post the policy's inputs to evaluate it for the customer. The body depends on the policy: this one declares a single requested_amount input, so that's the only key in inputs. Leaving out a declared input returns 400 with the code DecisionPolicy.MissingInputs, and an undeclared one returns DecisionPolicy.UnknownInputs.

curl -X POST "https://sandbox.walkerstdata.com.au/v1/customer/524ba9bc-06e7-417e-bd54-b99785f5194a/decision-policies/business-line-of-credit-v1/evaluate" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "inputs": { "requested_amount": 50000 } }'
{
"data": {
"verdict": {
"outcome": "conditional",
"recommendedActions": [
"Request the last three months of bank statements"
],
"reasons": []
},
"computedLimits": [
{
"kind": "computed",
"productId": "3f8d2a6c-91e4-4b7a-8d05-c6e3b1f92a47",
"amount": 150000,
"capped": true,
"uncappedAmount": 184640.25
}
],
"products": [
{
"productId": "3f8d2a6c-91e4-4b7a-8d05-c6e3b1f92a47",
"slug": "business-line-of-credit",
"name": "Business line of credit"
}
],
"indicators": [
{
"kind": "reading",
"metricId": "7c2e9f41-3b8a-4d6e-a15f-92d04b7e6c13",
"value": 2,
"format": "integer"
}
],
"metrics": [
{
"metricId": "7c2e9f41-3b8a-4d6e-a15f-92d04b7e6c13",
"name": "Dishonours last 90 days"
}
],
"attributes": [{ "name": "vedaScore", "value": 712.5, "source": "stored" }]
},
"message": null
}

6. Read the verdict​

  • verdict.outcome is the decision: proceed, conditional or blocked, taken from the first step that matched (or the policy's defaultOutcome if none did). It's indeterminate when the policy couldn't be decided, for example because a metric couldn't be calculated from the customer's transactions; verdict.reasons then explains why, each reason with a stable code (such as DecisionPolicy.MetricUnavailable), a message you can display and the metricIds involved.
  • verdict.recommendedActions lists the recommended action of every matched rule in the deciding step. Here, a conditional outcome asks for more statements before proceeding.
  • computedLimits has one entry per lending product the policy prices. A computed entry gives the limit amount; when a ceiling applied, capped is true and uncappedAmount shows the figure before the cap. An indeterminate entry has reasons instead of an amount. Match productId against products for the product's name and slug.
  • indicators are the metric readings the policy publishes alongside its verdict (with a format for display), and metrics gives each metric's name.
  • attributes shows every customer attribute the decision read and whether the value was stored or overridden.

To try a what-if without changing the customer's stored attributes, add attributeOverrides to the request, for example { "inputs": { "requested_amount": 50000 }, "attributeOverrides": { "vedaScore": 650 } }. To update the stored values, use Set customer attributes.

What's next​