curl --request POST \
--url https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"profile_seed": {
"factors": {
"dti_bam": 0.3
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({profile_seed: {factors: {dti_bam: 0.3}}})
};
fetch('https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate"
payload = { "profile_seed": { "factors": { "dti_bam": 0.3 } } }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"steps": [],
"decisions": [],
"path": [
"start",
"end"
],
"total_time_ms": 42,
"result": "approve",
"end_node_id": "end",
"score": 742,
"score_result": null,
"profile": {
"borrower_name": "Demo borrower"
},
"borrower_name": "Demo borrower"
}{
"detail": "Flow has no Start node."
}{
"detail": "Invalid or expired token"
}{
"detail": "Insufficient permissions"
}{
"detail": "Flow not found"
}{
"detail": [
{
"type": "missing",
"loc": [
"body",
"bank_code"
],
"msg": "Field required",
"input": {}
}
]
}{
"code": "rate_limit_exceeded",
"message": "Too many requests. Please slow down."
}Simulate a flow
Who can call it: Any signed-in member of the workspace.
Runs the flow on a synthetic borrower with the workspace’s active scoring policy. Nothing is stored. profile_seed overrides profile fields.
Auth: dashboard session (Authorization: Bearer <access token>). Not available with a partner API key.
curl --request POST \
--url https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"profile_seed": {
"factors": {
"dti_bam": 0.3
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({profile_seed: {factors: {dti_bam: 0.3}}})
};
fetch('https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.sahlfinancial.com/api/v1/flows/{flow_id}/simulate"
payload = { "profile_seed": { "factors": { "dti_bam": 0.3 } } }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"steps": [],
"decisions": [],
"path": [
"start",
"end"
],
"total_time_ms": 42,
"result": "approve",
"end_node_id": "end",
"score": 742,
"score_result": null,
"profile": {
"borrower_name": "Demo borrower"
},
"borrower_name": "Demo borrower"
}{
"detail": "Flow has no Start node."
}{
"detail": "Invalid or expired token"
}{
"detail": "Insufficient permissions"
}{
"detail": "Flow not found"
}{
"detail": [
{
"type": "missing",
"loc": [
"body",
"bank_code"
],
"msg": "Field required",
"input": {}
}
]
}{
"code": "rate_limit_exceeded",
"message": "Too many requests. Please slow down."
}Authorizations
The access token (JWT) of a signed-in console user, from POST /v1/auth/login. It lasts 30 minutes. It is not an API key: a partner API key is refused here. There is no cookie.
Path Parameters
Body
Optional body for the simulate endpoint.
profile_seed lets a caller override any field of the synthetic
borrower profile (e.g. {"factors": {"dti_bam": 0.3}} to push DTI
into review territory). Useful for demoing edge cases without
rewriting the policy.
Response
OK
Full simulation result for a flow.