Create a decision
POST /v1/decide answers every question in the request about one state.
POST https://api.finic.ai/v1/decideTakes a state and a set of named, typed questions, and returns a probability distribution for every question. For background, see State, Questions and Answers and probabilities.
Headers
| Header | Value |
|---|---|
Authorization | Required. Bearer gsk_…. See Authentication |
Content-Type | application/json |
Request body
| Field | Type | Description |
|---|---|---|
model | string | Required. grayson-1. An unknown model returns 404 model_not_found |
state | string, object or array | Required. Everything the questions are about. No schema. A string must not be blank. Objects and arrays are read as compact JSON, with key order kept |
questions | object | Required. 1–128 questions, keyed by name. Names match ^[A-Za-z_][A-Za-z0-9_]{0,63}$ |
Unknown fields are rejected, at the top level and in every question.
Question
| Field | Type | Applies to | Description |
|---|---|---|---|
type | string | All | Required. noul (yes/no), choice, multi_choice or score |
instructions | string | All | Required. The question, in words. Must not be blank |
options | object | choice, multi_choice | Required. 2–255 entries of key: description. Keys match the name pattern. Descriptions must not be blank and must be unique, ignoring case and whitespace. A choice reads them together, in order; a multi_choice asks about each one separately |
levels | array of strings | score | Required. 2–32 levels, lowest first. Must not be blank and must be unique, ignoring case and whitespace |
values | array of numbers | score | Optional. One finite number per level, strictly increasing. Defaults to 0, 1, …, K−1 |
Response
A successful call returns 200 with:
| Field | Type | Description |
|---|---|---|
id | string | The decision's id, starting with dec_ |
model | string | The model that answered, grayson-1 |
answers | object | One answer per question, keyed by question name |
usage.input_tokens | integer | Tokens the model read. See How tokens are counted |
Every response from the API, including errors, has an X-Request-Id header. Include it when you contact support.
Answer
Every answer has type, repeating its question's type, plus these fields:
| Type | Field | Type | Description |
|---|---|---|---|
noul | value | boolean | probability >= 0.5 |
probability | number | P(yes), from 0 to 1 | |
choice | value | string | The most likely option's key |
probabilities | object | One entry per option, in request order, summing to 1 | |
multi_choice | values | array of strings | Keys of the options with probability of at least 0.5, in request order |
probabilities | object | P(option applies) for each option, in request order. Independent, so they need not sum to 1 | |
score | value | number | The expected value: the sum of P(level) × the level's value |
level | string | The most likely level | |
probabilities | array of numbers | One entry per level, lowest first, summing to 1 |
Probabilities are not rounded. Nothing is generated: a response has no text beyond these fields.
Example
Save the request body below as request.json, then send it:
curl https://api.finic.ai/v1/decide \
-H "Authorization: Bearer $GRAYSON_API_KEY" \
-H "Content-Type: application/json" \
--data @request.json{
"model": "grayson-1",
"state": {
"account": {
"id": "acct_8812",
"opened": "2026-08-30",
"kyc": {
"name": "Dana Ruiz",
"dob": "1994-03-11",
"ssn_last4": "4410"
}
},
"events": [
{
"ts": "2026-09-20T02:14:09Z",
"type": "login",
"ip": "203.0.113.4",
"device_id": "d_77a1",
"new_device": true
},
{
"ts": "2026-09-20T02:16:40Z",
"type": "email_change",
"old": "dana.r@example.com",
"new": "dr8812@example.net"
},
{
"ts": "2026-09-20T02:21:03Z",
"type": "ach_out",
"amount": 4900.0,
"counterparty": "External bank account x9921",
"memo": "rent"
}
],
"support_notes": "Customer called 9/21 saying they never changed their email and don't recognize the transfer."
},
"questions": {
"is_fraud": {
"type": "noul",
"instructions": "Is this account engaged in or the victim of fraud?"
},
"ato_signs": {
"type": "noul",
"instructions": "Are there signs of account takeover?"
},
"primary_typology": {
"type": "choice",
"instructions": "What is the most likely primary fraud typology?",
"options": {
"ato": "Account takeover",
"synthetic_id": "Synthetic identity",
"mule": "Money mule activity",
"first_party": "First-party / bust-out",
"none": "No fraud indicated"
}
},
"typologies_present": {
"type": "multi_choice",
"instructions": "Which of these fraud typologies are present on this account?",
"options": {
"ato": "Account takeover",
"synthetic_id": "Synthetic identity",
"mule": "Money mule activity",
"first_party": "First-party / bust-out",
"scam": "Authorized push payment scam"
}
},
"risk": {
"type": "score",
"instructions": "How risky is the outbound ACH transfer?",
"levels": [
"very low",
"low",
"medium",
"high",
"very high"
]
}
}
}The response, with probabilities shortened to two decimals (responses carry full precision):
{
"id": "dec_01J8Z4Q7XK3MZ6T2W9D5HC0N4E",
"model": "grayson-1",
"answers": {
"is_fraud": {
"type": "noul",
"value": true,
"probability": 0.92
},
"ato_signs": {
"type": "noul",
"value": true,
"probability": 0.94
},
"primary_typology": {
"type": "choice",
"value": "ato",
"probabilities": {
"ato": 0.88,
"synthetic_id": 0.02,
"mule": 0.05,
"first_party": 0.03,
"none": 0.02
}
},
"typologies_present": {
"type": "multi_choice",
"values": [
"ato",
"mule"
],
"probabilities": {
"ato": 0.93,
"synthetic_id": 0.04,
"mule": 0.61,
"first_party": 0.03,
"scam": 0.07
}
},
"risk": {
"type": "score",
"value": 3.46,
"level": "very high",
"probabilities": [
0.01,
0.02,
0.07,
0.3,
0.6
]
}
},
"usage": {
"input_tokens": 587
}
}risk.value is the expected value on the default scale of 0 to 4: 0 × 0.01 + 1 × 0.02 + 2 × 0.07 + 3 × 0.3 + 4 × 0.6 = 3.46.