Deciders

Request a decision with inline questions

Evaluates questions sent with the request against input, answered by the agent or tool the request names (exactly one of agent_id and tool_id, held to the same rules as a decider's backend), and records the decision with its questions. The request and answers are those of OpenAI's Decisions API, with the backend in place of model.

No decider names the questions, so the decision carries them in questions and has no decider_id or decider_version. Admission, wait and the tool contract are those of POST /v1/projects/{project_id}/deciders/{decider_id}/decisions.

post/v1/projects/{project_id}/decisions

Request

  • Base URL: https://api.naturali.ai
  • URL: https://api.naturali.ai/v1/projects/{project_id}/decisions
  • Auth: one of:
    • HTTP bearer
    • OAuth 2 (authorization code, authorization URL https://api.naturali.ai/authorize, token URL https://api.naturali.ai/token, scopes: mcp:access)

Request body

agent_idstring

A tool-less agent that answers

tool_idstring

An http or pipeline tool that answers

inputstring required

What is judged, not stored: a string; a list of user messages whose content is a string or input_text and input_image parts (an image as a base64 data URL); or any other JSON value, which an agent is shown as indented JSON. An array of objects carrying role is read as messages.

metadataMetadataBag

Caller-owned annotations on a resource, stored as the object they were written as: the types a value was written with are the types a read returns, so a filter can ask an ordering question about a number. Unlike other body fields, keys are stored and returned verbatim in the casing supplied — they are not converted between snake_case and camelCase.

No key is reserved, and that is the point: every piece of state the platform owns lives in its own typed column, so nothing written here reaches platform state. The platform never reads the bag — it is not an IAM context, not a policy input and not part of a prompt — which is what separates it from a tag bag.

waitboolean

True evaluates before answering and returns the settled decision. False — the default — returns the queued decision at once. An MCP tool call always waits.

Example request

{
  "agent_id": "agent_V1StGXR8Z5jdHi6B",
  "tool_id": "tool_V1StGXR8Z5jdHi6B",
  "questions": [
    {
      "type": "choice",
      "name": "department",
      "instructions": "Which department should handle this complaint?",
      "choices": [
        {
          "value": "billing",
          "description": "Payments, invoices and refunds."
        },
        {
          "value": "technical",
          "description": "Problems using the product."
        }
      ]
    },
    {
      "type": "predicate",
      "name": "needs_human",
      "instructions": "Must a person read this before any automated reply?"
    }
  ],
  "input": "I was charged twice for the same order.",
  "metadata": {
    "author": "John",
    "revision": 2
  },
  "wait": true
}

Response

The decision — queued, or settled when wait is true

idstring
project_idstring
decider_idstring nullable

The decider asked; kept after the decider is deleted. Null for a decision sent with its own questions.

decider_versioninteger nullable

The question-set version the decision was answered under

status'queued' | 'running' | 'completed' | 'failed'
answers_by_nameobject nullable

The same answers keyed by question name, so a JSON Logic path reads one by name (answers_by_name.department.choice) rather than by position.

generation_idstring nullable

The generation that answered, once one has; null for a tool backend. Its receipt carries what the decision cost.

metadataMetadataBag

Caller-owned annotations on a resource, stored as the object they were written as: the types a value was written with are the types a read returns, so a filter can ask an ordering question about a number. Unlike other body fields, keys are stored and returned verbatim in the casing supplied — they are not converted between snake_case and camelCase.

No key is reserved, and that is the point: every piece of state the platform owns lives in its own typed column, so nothing written here reaches platform state. The platform never reads the bag — it is not an IAM context, not a policy input and not part of a prompt — which is what separates it from a tag bag.

created_atstring date-time
updated_atstring date-time

Example response

{
  "id": "dec_V1StGXR8Z5jdHi6B",
  "project_id": "proj_V1StGXR8Z5jdHi6B",
  "decider_id": "dcd_V1StGXR8Z5jdHi6B",
  "decider_version": 1,
  "questions": [
    {
      "type": "choice",
      "name": "department",
      "instructions": "Which department should handle this complaint?",
      "choices": [
        {
          "value": "billing",
          "description": "Payments, invoices and refunds."
        }
      ],
      "levels": [
        {
          "label": "Workaround available",
          "description": "A task fails, but another way works."
        }
      ]
    }
  ],
  "answers": [
    {
      "name": "department",
      "probability": 0.92,
      "choice": "billing",
      "score": 1.1,
      "probabilities": [
        {
          "probability": 0.95
        }
      ],
      "confidence": 0.93
    }
  ],
  "error": {
    "code": "AI_PROVIDER_ERROR",
    "message": "Provider returned 402: insufficient credits"
  },
  "generation_id": "gen_V1StGXR8Z5jdHi6B",
  "metadata": {
    "author": "John",
    "revision": 2
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.