Deciders

Request a decision

Evaluates the decider against input and records the decision. The questions come from the decider, never from the request, so a call site can only supply what is judged. To send the questions with the request, use POST /v1/projects/{project_id}/decisions.

Everything that can refuse the request is checked before the decision is written, so a refusal is a 4xx and never a polled failure: the agent's tool surface (400 DECIDER_AGENT_NOT_TOOL_LESS), a tool that cannot answer (400 DECIDER_TOOL_NOT_CALLABLE), a paused project (409 PROJECT_PAUSED) and, for an agent, quota admission (429 QUOTA_EXCEEDED).

A tool backend is called with { input, questions } and must answer { answers: [{ name, probability | choice | score, probabilities?, confidence? }] }, the request and response of OpenAI's Decisions API; an answer outside that contract fails the decision with DECISION_ANSWER_INVALID.

With wait: false, the default, the answer is 201 with the decision queued; poll GET /v1/projects/{project_id}/decisions/{decision_id} or subscribe to decisions.completed and decisions.failed. With wait: true it is 201 with the decision settled.

post/v1/projects/{project_id}/deciders/{decider_id}/decisions

Request

  • Base URL: https://api.naturali.ai
  • URL: https://api.naturali.ai/v1/projects/{project_id}/deciders/{decider_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)

Path parameters

decider_idstring required
Example:dcd_V1StGXR8Z5jdHi6B

The decider ID

Request body

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

{
  "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.