# Botify Agent: AI Decisions Gateway

**ID:** `ai_decisions_gateway`

Classify text with typed questions and get each answer's confidence


    Answer typed questions about a text with OpenAI's Decisions API, which picks
    answers instead of writing them: faster and cheaper than ai_gateway for
    classifying, routing, flagging or scoring, and every answer comes with how
    sure the model is. Use ai_gateway when something has to be written.

    The text to judge goes in user_prompt. The questions go in
    structured_output_json_schema, one per field, with the field's description as
    its question, and system_prompt holds framing shared by every question. A
    field name cannot contain a dot. Put a description on every field: a field
    without one is asked by its name.
    Each field must be one of: boolean (yes/no); enum of strings or whole numbers (pick one, up to 255 options); array of an enum (yes/no per option); number with minimum 0 and maximum 1 (the probability itself); integer levels 0..N with a description per level in anyOf/const (a score, up to 10 levels); or an object of these. At most 200 questions per text, counting one per
    option of an array field.

    structured_output mirrors the schema, with each field replaced by
    {"value": ..., "confidence": ..., "probabilities": ..., "score": ...}, so it
    does not validate against the schema itself. confidence runs from 0 to 1; a
    probability field has none, being a probability already. A score's value is
    its continuous score rounded to the nearest level, which can land between two
    likely levels on one the model gave no weight to: read probabilities for the
    likeliest level.
    

## Authentication

All endpoints require a **Bearer token** in the `Authorization` header.

```
Authorization: Bearer <your-token>
```

## Calling this agent

This agent supports the following processing modes:

| Mode | Type | Description |
|------|------|-------------|
| **Process** | Synchronous | Single-item processing. Best for real-time requests with immediate response. |
| **Batch Process** | Synchronous | Process multiple items in a single request for efficiency. |
| **Async Process** | Asynchronous | Single-item processing for long-running tasks that exceed timeout limits. |
| **Async Batch Process** | Asynchronous | Large-scale batch jobs with background processing. |

# Synchronous Processing

Synchronous calls block until the result is ready. Use these for quick operations where you need immediate results.

## Single Item Processing

Process a single input and receive the result immediately.

```
POST https://agents.botify.com/{org}/{project}/ai_decisions_gateway/process
```

### Request body

```json
{
  "item": {
    "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
  },
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}
```

### Response

Returns a single processed item (HTTP 200).

### cURL example

```bash
curl -X POST "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/process" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "item": {
    "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
  },
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}'
```

## Batch Processing

Process multiple inputs in a single synchronous request. More efficient than making individual calls. Items are processed concurrently on the server.

```
POST https://agents.botify.com/{org}/{project}/ai_decisions_gateway/batch_process
```

### Request body

```json
{
  "items": [
    {
      "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
    }
  ],
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}
```

### Response

Returns an array of results. Each element is either a successful processed item (`"status": "success"`) or an error (`"status": "error"`).

### cURL example

```bash
curl -X POST "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/batch_process" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
    }
  ],
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}'
```

### When to use synchronous calls

- Processing completes within timeout limits (typically 30 seconds)
- You need immediate results for user-facing features
- Small to medium batch sizes (up to ~100 items)

# Asynchronous Processing

Asynchronous calls return immediately with a batch ID. You then poll for results using the `async_batches/` endpoints.

### Async processing flow

1. **Submit job** -- `POST` to `async_process` or `async_batch_process`
2. **Receive batch ID** -- response contains `batch_id`
3. **Poll status** -- `HEAD` request to check readiness (lightweight, no body)
4. **Get results** -- `GET` request to retrieve processed results

## Async Single Item

Submit a single item for background processing. Use the `/single` endpoint to retrieve the result.

```
POST https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_process
```

### Request body

```json
{
  "item": {
    "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
  },
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}
```

### cURL example

```bash
# Step 1: Submit the job
curl -X POST "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_process" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "item": {
    "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
  },
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}'

# Response: { "batch_id": "abc123" }

# Step 2: Check if batch is ready (HEAD request -- lightweight check)
curl -I -X HEAD "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/abc123" \
  -H "Authorization: Bearer $TOKEN"
# Returns 200 if ready, 204 if still processing

# Step 3: Get the result (for single-item async)
curl -X GET "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/abc123/single" \
  -H "Authorization: Bearer $TOKEN"
# Returns 200 with result, 202 if still processing, 404 if batch not found
```

## Async Batch Processing

Submit multiple items for background processing. The request body uses **JSONL** (newline-delimited JSON) format.

```
POST https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batch_process
```

### Request body (JSONL, `Content-Type: text/plain`)

The first line contains `config` and `batch_config`. Each subsequent line is an item with a unique `id`.

```
{"config": {"structured_output_json_schema": {"properties": {"team": {"description": "Which team should handle this ticket?", "enum": ["billing", "logistics", "tech"]}, "angry": {"description": "Is the customer angry?", "type": "boolean"}, "topics": {"description": "Which topics does the ticket raise?", "items": {"enum": ["refund", "delay", "damage"]}, "type": "array"}, "refund_likelihood": {"description": "How likely is the customer to ask for a refund?", "maximum": 1, "minimum": 0, "type": "number"}, "severity": {"anyOf": [{"const": 0, "description": "cosmetic"}, {"const": 1, "description": "annoying"}, {"const": 2, "description": "blocking"}, {"const": 3, "description": "data loss"}], "description": "How severe is the issue?", "type": "integer"}}, "required": ["team", "angry", "topics", "refund_likelihood", "severity"], "type": "object"}}, "batch_config": {}}
{"id": "item_1", "item": {"user_prompt": "My parcel never arrived and nobody answers. Refund me now!"}}
```

### Response

Returns a JSON object with `batch_id`, `status`, and a `Location` header.

### cURL example

```bash
# Step 1: Submit the batch job
curl -X POST "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batch_process" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: text/plain" \
  -d '{"config": {"structured_output_json_schema": {"properties": {"team": {"description": "Which team should handle this ticket?", "enum": ["billing", "logistics", "tech"]}, "angry": {"description": "Is the customer angry?", "type": "boolean"}, "topics": {"description": "Which topics does the ticket raise?", "items": {"enum": ["refund", "delay", "damage"]}, "type": "array"}, "refund_likelihood": {"description": "How likely is the customer to ask for a refund?", "maximum": 1, "minimum": 0, "type": "number"}, "severity": {"anyOf": [{"const": 0, "description": "cosmetic"}, {"const": 1, "description": "annoying"}, {"const": 2, "description": "blocking"}, {"const": 3, "description": "data loss"}], "description": "How severe is the issue?", "type": "integer"}}, "required": ["team", "angry", "topics", "refund_likelihood", "severity"], "type": "object"}}, "batch_config": {}}\n{"id": "item_1", "item": {"user_prompt": "My parcel never arrived and nobody answers. Refund me now!"}}'

# Response: { "batch_id": "xyz789" }

# Step 2: Check if batch is ready (HEAD request)
curl -I -X HEAD "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/xyz789" \
  -H "Authorization: Bearer $TOKEN"
# Returns 200 if ready, 204 if still processing

# Step 3: Get all results
curl -X GET "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/xyz789" \
  -H "Authorization: Bearer $TOKEN"
```

## Checking Batch Status

Use a lightweight `HEAD` request to check if your batch is ready without transferring data.

```
HEAD https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/{batch_id}
```

```bash
curl -I -X HEAD "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/{batch_id}" \
  -H "Authorization: Bearer $TOKEN"

# Response headers indicate status:
# HTTP/1.1 200 OK        -> Batch is complete, results ready
# HTTP/1.1 204 No Content -> Still processing
# HTTP/1.1 404 Not Found -> Batch does not exist
```

## Retrieving Results

Once the batch is ready, fetch results using the appropriate endpoint.

```bash
# For async_process (single item) -- use /single endpoint
curl -X GET "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/{batch_id}/single" \
  -H "Authorization: Bearer $TOKEN"

# For async_batch_process (multiple items) -- use base endpoint
curl -X GET "https://agents.botify.com/{org}/{project}/ai_decisions_gateway/async_batches/{batch_id}" \
  -H "Authorization: Bearer $TOKEN"
# Returns streaming JSONL where each line is a processed item or error
```

### Async response codes

| Code | Endpoint | Meaning | Action |
|------|----------|---------|--------|
| 200 | `HEAD` / `GET` | Batch complete, results ready | Read results from response body |
| 204 | `HEAD` | Still processing | Continue polling |
| 202 | `GET /single` | Still processing | Continue polling |
| 400 | `GET /single` | All items failed (client error) | Check error in response body |
| 404 | `HEAD` / `GET` | Batch does not exist | Verify `batch_id` is correct |

> **HEAD vs GET:** Use `HEAD` requests for lightweight status checks (no response body). Use `GET` only when ready to retrieve results to minimize bandwidth.

### When to use asynchronous calls

- Processing takes longer than 30 seconds
- Large batch sizes (100+ items)
- Background processing where immediate results aren't required
- Integration with job queues or workflow systems

## Python Example

A complete Python example showing both synchronous and asynchronous patterns.

```python
import requests
import time

API_TOKEN = "your_api_token"
BASE_URL = "https://agents.botify.com/{organization}/{project}"
AGENT = "ai_decisions_gateway"

headers = {
    "Authorization": f"Bearer {API_TOKEN}",
    "Content-Type": "application/json"
}

single_payload = {
  "item": {
    "user_prompt": "My parcel never arrived and nobody answers. Refund me now!"
  },
  "config": {
    "structured_output_json_schema": {
      "properties": {
        "team": {
          "description": "Which team should handle this ticket?",
          "enum": [
            "billing",
            "logistics",
            "tech"
          ]
        },
        "angry": {
          "description": "Is the customer angry?",
          "type": "boolean"
        },
        "topics": {
          "description": "Which topics does the ticket raise?",
          "items": {
            "enum": [
              "refund",
              "delay",
              "damage"
            ]
          },
          "type": "array"
        },
        "refund_likelihood": {
          "description": "How likely is the customer to ask for a refund?",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "severity": {
          "anyOf": [
            {
              "const": 0,
              "description": "cosmetic"
            },
            {
              "const": 1,
              "description": "annoying"
            },
            {
              "const": 2,
              "description": "blocking"
            },
            {
              "const": 3,
              "description": "data loss"
            }
          ],
          "description": "How severe is the issue?",
          "type": "integer"
        }
      },
      "required": [
        "team",
        "angry",
        "topics",
        "refund_likelihood",
        "severity"
      ],
      "type": "object"
    }
  }
}


def process_sync(payload: dict) -> dict:
    """Synchronous single-item processing."""
    response = requests.post(
        f"{BASE_URL}/{AGENT}/process",
        headers=headers,
        json=payload
    )
    response.raise_for_status()
    return response.json()


def process_async(
    payload: dict,
    poll_interval: int = 5,
    max_retries: int = 60
) -> dict:
    """Asynchronous single-item processing with polling."""
    # Submit job
    response = requests.post(
        f"{BASE_URL}/{AGENT}/async_process",
        headers=headers,
        json=payload
    )
    batch_id = response.json()["batch_id"]

    # Poll for results using HEAD (lightweight check)
    for _ in range(max_retries):
        status = requests.head(
            f"{BASE_URL}/{AGENT}/async_batches/{batch_id}",
            headers=headers
        )

        if status.status_code == 200:
            result = requests.get(
                f"{BASE_URL}/{AGENT}/async_batches/{batch_id}/single",
                headers=headers
            )
            return result.json()
        elif status.status_code == 204:
            time.sleep(poll_interval)
        else:
            raise Exception(f"Unexpected status: {status.status_code}")

    raise Exception("Max retries exceeded")


def process_async_batch(
    items: list,
    config: dict | None = None,
    poll_interval: int = 5
) -> dict:
    """Asynchronous batch processing with polling."""
    import json as _json

    # Build JSONL payload: first line is config, subsequent lines are items
    lines = [_json.dumps({"config": config or {}, "batch_config": {}})]
    for i, item in enumerate(items):
        lines.append(_json.dumps({"id": f"item_{i}", "item": item}))
    body = "\n".join(lines)

    # Submit batch (JSONL, text/plain)
    response = requests.post(
        f"{BASE_URL}/{AGENT}/async_batch_process",
        headers={**headers, "Content-Type": "text/plain"},
        data=body
    )
    batch_id = response.json()["batch_id"]

    # Poll until ready
    while True:
        status = requests.head(
            f"{BASE_URL}/{AGENT}/async_batches/{batch_id}",
            headers=headers
        )

        if status.status_code == 200:
            results = requests.get(
                f"{BASE_URL}/{AGENT}/async_batches/{batch_id}",
                headers=headers
            )
            return results.json()

        time.sleep(poll_interval)


# Example usage
# result = process_sync(single_payload)
# result = process_async(single_payload)
# results = process_async_batch([{"input": "item1"}, {"input": "item2"}])
```

## Billing

Fixed cost per call plus input tokens only -- no output tokens. Prefeed agents are billed on top, at their own rates.

These usage SKUs can be charged on a call.

| SKU | Credits | Description |
| --- | ------- | ----------- |
| Tool call | 1 per request | Charged once per successful item, on top of any usage below. |
| GPT-6 Luna (Decisions) (standard), input | 100 per million tokens | Tokens the model reads from the prompt you send. |


## Schemas

### Item

```json
{
  "type": "object",
  "properties": {
    "prefeed": {
      "default": [],
      "description": "List of agent pre-calls whose results are injected into the user prompt before the LLM runs.",
      "items": {
        "$ref": "#/$defs/PrefeedCall"
      },
      "title": "Prefeed",
      "type": "array"
    },
    "user_prompt": {
      "description": "The text to judge. Put the questions in structured_output_json_schema and system_prompt: a question written here is judged as text, not asked.",
      "examples": [
        "My parcel never arrived and nobody answers. Refund me now!"
      ],
      "title": "User Prompt",
      "type": "string"
    }
  },
  "required": [
    "user_prompt"
  ],
  "$defs": {
    "PrefeedCall": {
      "description": "A pre-call to an agent whose result is injected into the user prompt before the LLM runs.",
      "properties": {
        "description": {
          "description": "Description of the prefeed result (used as context label in the prompt)",
          "title": "Description",
          "type": "string"
        },
        "agent": {
          "description": "Agent ID to call",
          "title": "Agent",
          "type": "string"
        },
        "item": {
          "additionalProperties": true,
          "description": "Item payload for the agent",
          "title": "Item",
          "type": "object"
        },
        "config": {
          "additionalProperties": true,
          "default": {},
          "description": "Optional config payload for the agent",
          "title": "Config",
          "type": "object"
        }
      },
      "required": [
        "description",
        "agent",
        "item"
      ],
      "title": "PrefeedCall",
      "type": "object"
    }
  }
}
```

### Config

```json
{
  "type": "object",
  "properties": {
    "prefeed": {
      "default": [],
      "description": "List of agent pre-calls whose results are injected into the user prompt before the LLM runs.",
      "items": {
        "$ref": "#/$defs/PrefeedCall"
      },
      "title": "Prefeed",
      "type": "array"
    },
    "system_prompt": {
      "default": "",
      "description": "Framing shared by every question: what the texts are and what they are judged for.",
      "title": "System Prompt",
      "type": "string"
    },
    "structured_output_json_schema": {
      "additionalProperties": true,
      "description": "A JSON Schema of \"type\": \"object\" whose properties are the questions: each property is one question, its description is the question asked, and its type is the kind of answer. Each field must be one of: boolean (yes/no); enum of strings or whole numbers (pick one, up to 255 options); array of an enum (yes/no per option); number with minimum 0 and maximum 1 (the probability itself); integer levels 0..N with a description per level in anyOf/const (a score, up to 10 levels); or an object of these. See the example for one field of each kind.",
      "examples": [
        {
          "properties": {
            "team": {
              "description": "Which team should handle this ticket?",
              "enum": [
                "billing",
                "logistics",
                "tech"
              ]
            },
            "angry": {
              "description": "Is the customer angry?",
              "type": "boolean"
            },
            "topics": {
              "description": "Which topics does the ticket raise?",
              "items": {
                "enum": [
                  "refund",
                  "delay",
                  "damage"
                ]
              },
              "type": "array"
            },
            "refund_likelihood": {
              "description": "How likely is the customer to ask for a refund?",
              "maximum": 1,
              "minimum": 0,
              "type": "number"
            },
            "severity": {
              "anyOf": [
                {
                  "const": 0,
                  "description": "cosmetic"
                },
                {
                  "const": 1,
                  "description": "annoying"
                },
                {
                  "const": 2,
                  "description": "blocking"
                },
                {
                  "const": 3,
                  "description": "data loss"
                }
              ],
              "description": "How severe is the issue?",
              "type": "integer"
            }
          },
          "required": [
            "team",
            "angry",
            "topics",
            "refund_likelihood",
            "severity"
          ],
          "type": "object"
        }
      ],
      "title": "Structured Output Json Schema",
      "type": "object"
    },
    "model_settings": {
      "$ref": "#/$defs/OpenAIDecisionsSettings",
      "description": "The decision model and how it turns probabilities into answers"
    }
  },
  "required": [
    "structured_output_json_schema"
  ],
  "$defs": {
    "OpenAIDecisionsSettings": {
      "description": "A model on OpenAI's Decisions API.",
      "properties": {
        "boolean_threshold": {
          "default": 0.5,
          "description": "How likely a yes has to be before a boolean field is true, from 0 to 1. Raise it where a false positive is the expensive mistake.",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Boolean Threshold",
          "type": "number"
        },
        "model": {
          "const": "gpt-6-luna",
          "description": "The model, by its bare name (no provider prefix).",
          "title": "Model",
          "type": "string"
        }
      },
      "required": [
        "model"
      ],
      "title": "OpenAIDecisionsSettings",
      "type": "object"
    },
    "PrefeedCall": {
      "description": "A pre-call to an agent whose result is injected into the user prompt before the LLM runs.",
      "properties": {
        "description": {
          "description": "Description of the prefeed result (used as context label in the prompt)",
          "title": "Description",
          "type": "string"
        },
        "agent": {
          "description": "Agent ID to call",
          "title": "Agent",
          "type": "string"
        },
        "item": {
          "additionalProperties": true,
          "description": "Item payload for the agent",
          "title": "Item",
          "type": "object"
        },
        "config": {
          "additionalProperties": true,
          "default": {},
          "description": "Optional config payload for the agent",
          "title": "Config",
          "type": "object"
        }
      },
      "required": [
        "description",
        "agent",
        "item"
      ],
      "title": "PrefeedCall",
      "type": "object"
    }
  }
}
```

### Response

```json
{
  "description": "The answers, each with how sure the model is",
  "properties": {
    "structured_output": {
      "additionalProperties": true,
      "description": "The schema's fields, each replaced by {value, confidence, probabilities, score}; keys that do not apply to a field are left out.",
      "title": "Structured Output",
      "type": "object"
    }
  },
  "required": [
    "structured_output"
  ],
  "title": "AIDecisionsGatewayProcessedItem",
  "type": "object"
}
```

## Best Practices

**Use exponential backoff for polling.** Start with short intervals (1-2 seconds) and increase the delay between polls to reduce API load.

**Set reasonable timeouts.** For synchronous calls, configure your HTTP client with appropriate timeout values (30-60 seconds).

**Handle rate limits gracefully.** Implement retry logic with backoff when you receive 429 (Too Many Requests) responses.

**Batch when possible.** Use batch endpoints to reduce the number of API calls and improve throughput.
