# Chat completions

> POST /v1/chat/completions nel formato OpenAI, con streaming, strumenti, immagini e ragionamento.


Richiesta e risposta di OpenAI Chat Completions, sui modelli NotHoly. Punta un SDK OpenAI sull'URL base e non cambiare nient'altro.

```endpoint
POST https://api.notholy.com/v1/chat/completions
```

## Richiesta

| Campo | Tipo | Obbligatorio | Note |
|---|---|---|---|
| `model` | string | Sì | Un ID di modello, per esempio `notholy-specter`. Vedi [Modelli](/it/getting-started/models) |
| `messages` | array | Sì | Ruoli `system`, `developer` (letto come `system`), `user`, `assistant` e `tool`. Il contenuto è una stringa o un elenco di parti `text` e `image_url` |
| `max_completion_tokens` / `max_tokens` | number | No | Limite di output. Se li imposti entrambi vince `max_completion_tokens`. Il predefinito è l'output massimo del modello; un valore più alto restituisce `400` |
| `stream` | boolean | No | `true` restituisce server-sent events. Vedi [Streaming](/it/guides/streaming) |
| `tools` | array | No | Solo strumenti di tipo funzione. Gli altri tipi restituiscono `400 unsupported_parameter` |
| `tool_choice` | string o object | No | Passato al modello quando `tools` è impostato |
| `reasoning_effort` | string | No | Uno dei `reasoning_efforts` del modello. Qualsiasi altro valore restituisce `400`. Vedi [Ragionamento](/it/guides/reasoning) |
| `response_format` | object | No | Passato al modello |
| `temperature`, `top_p`, `stop` | number, number, string o array | No | Passati al modello |
| `n` | number | No | Solo `1` |

I campi sconosciuti vengono ignorati. Le immagini sono accettate sui modelli i cui `input_modalities` includono `image`; sugli altri restituiscono `400 unsupported_parameter`.

## Risposta senza streaming

```json
{
  "id": "chatcmpl-8Kp2c1Vx",
  "object": "chat.completion",
  "created": 1793836800,
  "model": "notholy-specter",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "An IDOR lets a user read or change another user's object by changing its ID…",
        "refusal": null,
        "reasoning_content": "…"
      },
      "finish_reason": "stop",
      "logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 118,
    "total_tokens": 160,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 64 }
  }
}
```

- `reasoning_content` c'è solo quando il modello ha ragionato.
- Con le chiamate di strumenti, `message.tool_calls` contiene elementi `{id, type: "function", function: {name, arguments}}`, `finish_reason` è `tool_calls` e `content` è `null` quando non c'è testo.
- `finish_reason` è `stop`, `length`, `tool_calls` o `content_filter`.
- In streaming, l'ultimo chunk prima di `data: [DONE]` porta sempre `usage`, che tu invii o no `stream_options.include_usage`.

## Esempio

```bash test
curl https://api.notholy.com/v1/chat/completions \
  -H "Authorization: Bearer $NOTHOLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "notholy-specter",
    "messages": [
      {"role": "system", "content": "You are reviewing code for an authorized assessment."},
      {"role": "user", "content": "What does a missing ownership check in GET /api/invoices/:id lead to?"}
    ]
  }'
```

```python test
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.notholy.com/v1", api_key=os.environ["NOTHOLY_API_KEY"])

r = client.chat.completions.create(
    model="notholy-specter",
    messages=[{"role": "user", "content": "List three checks for an SSRF fix."}],
    max_tokens=400,
)
print(r.choices[0].message.content)
print(r.usage.prompt_tokens, r.usage.completion_tokens)
```

```js test
import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://api.notholy.com/v1', apiKey: process.env.NOTHOLY_API_KEY });

const r = await client.chat.completions.create({
  model: 'notholy-specter',
  messages: [{ role: 'user', content: 'List three checks for an SSRF fix.' }],
  max_tokens: 400,
});
console.log(r.choices[0].message.content);
```

## Header di risposta

| Header | Significato |
|---|---|
| `x-request-id` | Mandalo al supporto quando segnali un problema |
| `x-notholy-concurrency-limit` | Richieste che puoi eseguire insieme |
| `x-notholy-concurrency-remaining` | Slot liberi quando è partita questa richiesta |
| `x-notholy-credits-remaining` | Crediti disponibili in USD quando è partita questa richiesta |

## Errori

`400` corpo o parametro non valido · `401` chiave mancante o non valida · `402` crediti o budget della chiave insufficienti · `403` la chiave non può usare questo modello · `404` modello sconosciuto · `429` limite di richieste o di richieste simultanee (rispetta `retry-after`) · `502`/`504` il modello ha fallito o è andato in timeout · `503` modello non disponibile. Tabella completa: [Errori](/it/guides/errors).
