# Open API

> Un endpoint compatibile con OpenAI per i tuoi personaggi.

Source: https://reverie.im/it/docs/integrations/open-api
Language: it

Reverie espone un endpoint Chat Completions compatibile con OpenAI. Punta qualunque client OpenAI su di esso, passa una chiave API Reverie e usa il campo `model` per indicare un **personaggio o uno scenario** invece di un LLM. Reverie tiene dalla sua parte la conversazione, i ricordi e i riassunti, così ogni richiesta ha bisogno solo del tuo messaggio nuovo.

Può usarlo qualsiasi account con l'accesso fatto. Non c'è un livello di abbonamento né una lista d'attesa: serve una chiave API, e basta. [Creane una →](https://reverie.im/it/docs/integrations/api-keys)

## URL di base e autenticazione \[#base-url-and-auth]

```
https://www.reverie.im/api/device/v1
Authorization: Bearer rk_...
```

**Impostazioni → Altro → Chiavi API** mostra l'URL di base esatto nella scheda **API Endpoint**, con un pulsante per copiarlo.

> **Questa è un'API lato server.** Le richieste dal browser che arrivano da un'altra origine sono bloccate, quindi un fetch dalla tua pagina web fallisce comunque, chiave giusta o no. Chiamala da un backend e tieni la chiave fuori dal codice del client.

## Avvio rapido \[#quick-start]

**cURL**

```bash
curl --no-buffer https://www.reverie.im/api/device/v1/chat/completions \
  -H "Authorization: Bearer $REVERIE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary '{
  "model": "Luna [abc12345]",
  "messages": [
    {
      "role": "user",
      "content": "Hi"
    }
  ],
  "stream": true,
  "temperature": 0.8
}'
```

**Python**

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["REVERIE_API_KEY"],
    base_url="https://www.reverie.im/api/device/v1",
)

stream = client.chat.completions.create(
    model="Luna [abc12345]",   # an id from GET /models, a full character or scenario ID, or omit entirely
    messages=[{"role": "user", "content": "Hi"}],
    stream=True,
    temperature=0.8,
)

for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")
```

**TypeScript**

```ts
import OpenAI from "openai";

const client = new OpenAI({
	apiKey: process.env.REVERIE_API_KEY,
	baseURL: "https://www.reverie.im/api/device/v1",
});

const stream = await client.chat.completions.create({
	model: "Luna [abc12345]",
	messages: [{ role: "user", content: "Hi" }],
	stream: true,
	temperature: 0.8,
});

for await (const chunk of stream) {
	process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```

**Impostazioni → Altro → Chiavi API** ha anche un costruttore di richieste che genera questi tre frammenti usando una delle tue chiavi vere e un personaggio vero.

## Il campo `model` indica un personaggio \[#the-model-field-names-a-character]

> **Il solo nome del personaggio non funziona.** `model: "Luna"` non cerca un personaggio chiamato Luna. Non combacia con nulla, ricade sul personaggio predefinito della chiave o sulla tua chat più recente, e ti arriva la risposta di un altro personaggio senza alcun errore. Usa sempre la forma `Nome [idbreve]` che restituisce `GET /models`.

| Valore di `model`                                    | Chi risponde                                                                  |
| ---------------------------------------------------- | ----------------------------------------------------------------------------- |
| `Luna [abc12345]`                                    | Il personaggio o lo scenario il cui ID termina con quegli 8 caratteri         |
| Un ID completo di personaggio o scenario             | Quel personaggio o quello scenario                                            |
| Un ID di modello Reverie, ad es. `deepseek-v4-flash` | Sceglie l'**LLM**; il personaggio arriva dalla chiave o dalla tua ultima chat |
| Omesso                                               | Il personaggio fissato alla chiave, altrimenti la tua chat più recente        |

Dettagli che decidono se un ID breve si risolve:

* Il `[...]` deve stare alla **fine** della stringa.
* Un suffisso di 8 caratteri o meno viene confrontato solo con i personaggi **con cui hai già una chat**, sul web o tramite API. L'ID breve di un personaggio mai aperto fallisce in silenzio.
* La ricerca dello scenario parte solo quando la chiave è fissata a un personaggio. Con una chiave globale, un ID breve di scenario non si risolve mai.
* Oltre gli 8 caratteri viene trattato come ID completo.

### Elencare con chi puoi parlare \[#listing-what-you-can-talk-to]

```bash
curl https://www.reverie.im/api/device/v1/models \
  -H "Authorization: Bearer $REVERIE_API_KEY"
```

Una chiave **globale** restituisce i tuoi personaggi recenti. Una chiave **fissata a un personaggio** restituisce invece gli scenari di quel personaggio, o il personaggio stesso se non ne ha. Ogni voce è fatta così:

```json
{
	"id": "Luna [abc12345]",
	"object": "model",
	"created": 1759200000,
	"owned_by": "character",
	"permission": [],
	"root": "<full character id>",
	"parent": null
}
```

Copia `id` così com'è dentro `model`. Gli errori di questo endpoint usano una forma d'errore semplice invece dell'involucro OpenAI.

## Cosa legge il corpo della richiesta \[#what-the-request-body-reads]

Vengono letti quattro campi. Tutto il resto è accettato e scartato in silenzio.

| Campo         | Tipo       | Predefinito                                      | Note                                                                      |
| ------------- | ---------- | ------------------------------------------------ | ------------------------------------------------------------------------- |
| `messages`    | array      | obbligatorio                                     | Vedi sotto — se ne usa solo una parte                                     |
| `model`       | stringa    | facoltativo                                      | Personaggio, scenario o LLM, come sopra                                   |
| `stream`      | booleano   | **`true`**                                       | Lo streaming è il comportamento predefinito, al contrario dell'API OpenAI |
| `temperature` | numero 0–2 | l'impostazione del personaggio, altrimenti `0.8` | I valori fuori intervallo vengono rifiutati                               |

Ignorati senza avviso: `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Come viene trattato `messages`:

* **I messaggi `system` vengono scartati.** Personalità e comportamento vengono dai campi del personaggio, non dalla richiesta. [Campi del prompt →](https://reverie.im/it/docs/characters/prompt-fields)
* **Non c'è supporto per le immagini.** Il contenuto può essere una stringa o un array di parti, ma si leggono solo le parti `text`; le parti immagine sono ignorate.
* Alla conversazione viene aggiunto solo l'\*\*ultimo messaggio `user`\*\*. I messaggi utente precedenti sono ignorati.
* I messaggi dell'assistente servono solo a sincronizzare la cronologia (vedi sotto).
* Un ultimo messaggio utente vuoto o fatto di soli spazi restituisce `missing_user_message`.

## Risposte \[#responses]

Una risposta senza streaming è un normale oggetto `chat.completion`. `finish_reason` è sempre `stop` — le chiamate interne agli strumenti non vengono mai esposte — e i contatori di `usage` sono a zero, quindi misura i token dalle statistiche d'uso nella pagina delle chiavi API, non dalla risposta.

Una risposta in streaming è un `text/event-stream`:

1. Blocchi di contenuto: oggetti `chat.completion.chunk` con `delta.content`. \*&#x2A;Non viene inviato un blocco iniziale `delta: {"role": "assistant"}`.*\*
2. Un blocco di chiusura, con `finish_reason` pari a `stop`, `length` o `content_filter`. Le chiusure dovute a chiamate di strumenti sono riportate come `stop`.
3. Un blocco d'uso con l'array `choices` vuoto.
4. `data: [DONE]`.

Se la generazione fallisce a metà stream, lo stream emette `data: {"error": {...}}` e poi `[DONE]`.

## Stato della conversazione \[#conversation-state]

La conversazione la conserva Reverie. Esiste una chat per ogni coppia chiave-personaggio, compare nell'app web accanto alle tue altre chat, e ogni turno è costruito con il prompt di sistema e lo scenario del personaggio, il canone dei world book, i ricordi a lungo termine, i riassunti via via aggiornati, lo stile narrativo del personaggio, la lunghezza della risposta e le impostazioni NSFW, un blocco della lingua preso dalla lingua del tuo account, e tutta la cronologia recente che la finestra di contesto del modello riesce a contenere. Gli strumenti di memoria girano quando il modello li supporta.

Dato che la cronologia la tiene il server, non devi rimandarla.

> **Inviare messaggi dell'assistente può cancellare la cronologia.** Se il tuo array `messages` contiene messaggi dell'assistente, Reverie prende l'ultimo, lo cerca tra i 20 messaggi salvati più recenti e, se lo trova, cancella per sempre ogni messaggio creato dopo di esso, insieme ai ricordi nati dopo quel punto. Se non trova nulla, non cancella nulla. La lunghezza del tuo array non c'entra. Per evitarlo del tutto, manda solo il nuovo messaggio dell'utente.

## Quale LLM risponde \[#which-llm-answers]

Decide il personaggio, non la richiesta — a meno che tu non indichi un LLM. Precedenza, dalla più bassa alla più alta: il modello di chat predefinito, poi l'impostazione di modello del personaggio, poi un ID di modello Reverie passato come `model`, e infine la preferenza di modello che hai impostato per quella chat nell'app web, che batte tutte le altre. [Modelli →](https://reverie.im/it/docs/reference/models)

## Errori \[#errors]

Gli errori di `/chat/completions` usano l'involucro OpenAI: `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP      | `code`                 | `type`                  | Causa                                                                                 |
| --------- | ---------------------- | ----------------------- | ------------------------------------------------------------------------------------- |
| 401       | `invalid_api_key`      | `invalid_request_error` | `Authorization` mancante o malformato, chiave sconosciuta, o chiave non attiva        |
| 401       | `api_key_expired`      | `invalid_request_error` | La chiave ha superato la scadenza                                                     |
| 404       | `scenario_not_found`   | `invalid_request_error` | L'ID dello scenario si è risolto ma lo scenario non c'è più                           |
| 404       | `character_not_found`  | `invalid_request_error` | Il personaggio manca o è stato cancellato                                             |
| 404       | `no_chat_history`      | `invalid_request_error` | Niente `model`, nessun personaggio fissato e nessuna chat precedente su cui ripiegare |
| 400       | `missing_user_message` | `invalid_request_error` | Nessun messaggio `user` non vuoto                                                     |
| 429       | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Finestra dei modelli gratuiti esaurita. `Retry-After` indica i secondi da aspettare   |
| 429       | `insufficient_quota`   | `insufficient_quota`    | Crediti insufficienti per la richiesta                                                |
| 502       | `MODEL_EMPTY_RESPONSE` | `server_error`          | Il modello ha concluso senza errori ma senza testo                                    |
| variabile | codice del fornitore   | `server_error`          | Generazione fallita a monte                                                           |

Due casi restano fuori da quell'involucro: gli errori di `GET /models` e i corpi di richiesta respinti dalla validazione (una `temperature` fuori intervallo, per esempio) — entrambi restituiscono una forma d'errore semplice.

## Limiti di frequenza e quote \[#rate-limits-and-quotas]

Questa API **non ha limiti di frequenza per chiave, né un tetto di concorrenza, né una quota di richieste**. A limitare il tuo uso sono due cose sole:

| Vincolo                       | Valore                                                                                        |
| ----------------------------- | --------------------------------------------------------------------------------------------- |
| Saldo crediti                 | Controllato prima di ogni richiesta; se non basta restituisce `insufficient_quota`            |
| Finestra dei modelli gratuiti | 15 messaggi ogni 3 ore, per account — ×3 su Pro (45), ×4 su Premium (60), ×5 su Ultimate (75) |

La finestra dei modelli gratuiti è condivisa con la chat web, le storie, i romanzi e i bot: è un'unica dotazione per account, non una per ciascun posto. [Modelli gratuiti →](https://reverie.im/it/docs/reference/free-models)

Reverie non invia webhook in uscita; non c'è nulla a cui iscriversi per sapere quando una generazione è finita.

## Importare personaggi \[#importing-characters]

Un secondo endpoint, `POST /api/v1/characters/import`, crea un personaggio da una scheda personaggio. Richiede una chiave con l'ambito di importazione, che non è il tipo di chiave creato dalla pagina delle impostazioni. [Chiavi API →](https://reverie.im/it/docs/integrations/api-keys) e [Importare personaggi →](https://reverie.im/it/docs/characters/import-characters)

## Correlati \[#related]

* [Chiavi API](https://reverie.im/it/docs/integrations/api-keys) — creare, fissare, far scadere e tenere d'occhio le chiavi
* [Modelli](https://reverie.im/it/docs/reference/models) — ID dei modelli e moltiplicatori di crediti
* [Limiti](https://reverie.im/it/docs/reference/limits) — gli altri tetti del prodotto
* [Crediti](https://reverie.im/it/docs/billing/credits) — come vengono tariffate le richieste
