# API ouverte

> Un endpoint compatible OpenAI pour vos personnages.

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

Reverie expose un endpoint Chat Completions compatible OpenAI. Pointez n'importe quel client OpenAI dessus, passez une clé API Reverie, et utilisez le champ `model` pour nommer un **personnage ou un scénario** plutôt qu'un LLM. Reverie garde la conversation, les souvenirs et les résumés de son côté, si bien que chaque requête n'a besoin que de votre nouveau message.

N'importe quel compte connecté peut l'utiliser. Il n'y a ni palier d'abonnement ni liste d'attente — il vous faut une clé API, et c'est tout. [En créer une →](https://reverie.im/fr/docs/integrations/api-keys)

## URL de base et authentification \[#base-url-and-auth]

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

**Paramètres → Plus → Clés API** affiche l'URL de base exacte dans la carte **API Endpoint**, avec un bouton de copie.

> **C'est une API côté serveur.** Les requêtes de navigateur venant d'une autre origine sont bloquées : un fetch depuis votre propre page web échouera quelle que soit la clé. Appelez-la depuis un backend et gardez la clé hors du code client.

## Démarrage rapide \[#quick-start]

**cURL**

```bash
curl --no-buffer https://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://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://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 ?? "");
}
```

**Paramètres → Plus → Clés API** propose aussi un constructeur de requêtes qui génère ces trois extraits à partir d'une de vos vraies clés et d'un vrai personnage.

## Le champ `model` désigne un personnage \[#the-model-field-names-a-character]

> **Un simple nom de personnage ne marche pas.** `model: "Luna"` ne cherche pas un personnage nommé Luna. Il ne correspond à rien, retombe sur le personnage par défaut de la clé ou sur votre conversation la plus récente, et vous recevez la réponse d'un autre personnage sans la moindre erreur. Utilisez toujours la forme `Nom [idcourt]` que renvoie `GET /models`.

| Valeur de `model`                                    | Qui répond                                                                           |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `Luna [abc12345]`                                    | Le personnage ou le scénario dont l'ID se termine par ces 8 caractères               |
| Un ID complet de personnage ou de scénario           | Ce personnage ou ce scénario                                                         |
| Un ID de modèle Reverie, par ex. `deepseek-v4-flash` | Choisit le **LLM** ; le personnage vient de la clé ou de votre dernière conversation |
| Omis                                                 | Le personnage épinglé à la clé, sinon votre conversation la plus récente             |

Ce qui décide si un ID court se résout :

* Le `[...]` doit être à la **fin** de la chaîne.
* Un suffixe de 8 caractères ou moins n'est comparé qu'aux personnages **avec lesquels vous avez déjà une conversation**, sur le web ou via l'API. L'ID court d'un personnage jamais ouvert échoue silencieusement.
* La recherche de scénario ne s'exécute que lorsque la clé est épinglée à un personnage. Avec une clé globale, un ID court de scénario ne peut jamais se résoudre.
* Au-delà de 8 caractères, c'est traité comme un ID complet.

### Lister ce à quoi vous pouvez parler \[#listing-what-you-can-talk-to]

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

Une clé **globale** renvoie vos personnages récents. Une clé **épinglée à un personnage** renvoie plutôt les scénarios de ce personnage, ou le personnage lui-même s'il n'en a aucun. Chaque entrée ressemble à ceci :

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

Copiez `id` directement dans `model`. Les erreurs de cet endpoint utilisent une forme d'erreur simple plutôt que l'enveloppe OpenAI.

## Ce que le corps de la requête lit \[#what-the-request-body-reads]

Quatre champs sont lus. Tout le reste est accepté puis silencieusement écarté.

| Champ         | Type       | Par défaut                            | Remarques                                                |
| ------------- | ---------- | ------------------------------------- | -------------------------------------------------------- |
| `messages`    | tableau    | obligatoire                           | Voir plus bas — seule une partie est utilisée            |
| `model`       | chaîne     | facultatif                            | Personnage, scénario ou LLM, comme ci-dessus             |
| `stream`      | booléen    | **`true`**                            | Le streaming est le défaut, contrairement à l'API OpenAI |
| `temperature` | nombre 0–2 | le réglage du personnage, sinon `0.8` | Les valeurs hors plage sont rejetées                     |

Ignorés sans avertissement : `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Comment `messages` est traité :

* **Les messages `system` sont jetés.** La personnalité et le comportement viennent des champs du personnage, pas de la requête. [Champs du prompt →](https://reverie.im/fr/docs/characters/prompt-fields)
* **Il n'y a pas de support de la vision.** Le contenu peut être une chaîne ou un tableau de parties, mais seules les parties `text` sont lues ; les parties image sont ignorées.
* Seul le \*&#x2A;dernier message `user`*\* est ajouté à la conversation. Les messages utilisateur précédents sont ignorés.
* Les messages d'assistant ne servent qu'à la synchronisation de l'historique (ci-dessous).
* Un dernier message utilisateur vide ou composé d'espaces renvoie `missing_user_message`.

## Réponses \[#responses]

Une réponse sans streaming est un objet `chat.completion` classique. `finish_reason` vaut toujours `stop` — les appels d'outils internes ne sont jamais exposés — et les compteurs `usage` sont à zéro : mesurez les tokens depuis les statistiques d'usage de la page des clés API, pas depuis la réponse.

Une réponse en streaming est un `text/event-stream` :

1. Fragments de contenu : des objets `chat.completion.chunk` avec `delta.content`. \*&#x2A;Aucun fragment initial `delta: {"role": "assistant"}` n'est envoyé.*\*
2. Un fragment de fin, avec `finish_reason` valant `stop`, `length` ou `content_filter`. Les fins dues à un appel d'outil sont signalées comme `stop`.
3. Un fragment d'usage avec un tableau `choices` vide.
4. `data: [DONE]`.

Si la génération échoue en cours de route, le flux émet `data: {"error": {...}}` puis `[DONE]`.

## État de la conversation \[#conversation-state]

Reverie stocke la conversation. Il existe une conversation par couple clé-personnage, elle apparaît dans l'application web à côté de vos autres conversations, et chaque tour est bâti à partir du prompt système et du scénario du personnage, du canon des livres du monde, des souvenirs de long terme, des résumés successifs, du style de narration du personnage, de la longueur de réponse et des réglages NSFW, d'un verrou de langue tiré de la langue de votre compte, et d'autant d'historique récent que la fenêtre de contexte du modèle peut en contenir. Les outils de mémoire s'exécutent lorsque le modèle gère les outils.

Comme le serveur détient l'historique, vous n'avez pas à le rejouer.

> **Envoyer des messages d'assistant peut supprimer l'historique.** Si votre tableau `messages` contient des messages d'assistant, Reverie prend le dernier, le cherche parmi les 20 messages stockés les plus récents et, en cas de correspondance, supprime définitivement tous les messages créés après lui, ainsi que les souvenirs créés après ce point. Si rien ne correspond, rien n'est supprimé. La longueur de votre tableau n'y change rien. Pour éviter cela complètement, n'envoyez que le nouveau message utilisateur.

## Quel LLM répond \[#which-llm-answers]

C'est le personnage qui décide, pas la requête — sauf si vous nommez un LLM. Priorité, de la plus faible à la plus forte : le modèle de chat par défaut, puis le réglage de modèle du personnage, puis un ID de modèle Reverie passé dans `model`, et enfin la préférence de modèle que vous avez fixée pour cette conversation dans l'application web, qui l'emporte sur tout le reste. [Modèles →](https://reverie.im/fr/docs/reference/models)

## Erreurs \[#errors]

Les erreurs de `/chat/completions` utilisent l'enveloppe OpenAI : `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP     | `code`                 | `type`                  | Cause                                                                                     |
| -------- | ---------------------- | ----------------------- | ----------------------------------------------------------------------------------------- |
| 401      | `invalid_api_key`      | `invalid_request_error` | `Authorization` absent ou mal formé, clé inconnue, ou clé inactive                        |
| 401      | `api_key_expired`      | `invalid_request_error` | La clé a dépassé sa date d'expiration                                                     |
| 404      | `scenario_not_found`   | `invalid_request_error` | L'ID de scénario s'est résolu mais le scénario n'existe plus                              |
| 404      | `character_not_found`  | `invalid_request_error` | Le personnage est introuvable ou supprimé                                                 |
| 404      | `no_chat_history`      | `invalid_request_error` | Pas de `model`, pas de personnage épinglé et aucune conversation antérieure de repli      |
| 400      | `missing_user_message` | `invalid_request_error` | Aucun message `user` non vide                                                             |
| 429      | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Fenêtre de modèles gratuits épuisée. `Retry-After` donne le nombre de secondes à attendre |
| 429      | `insufficient_quota`   | `insufficient_quota`    | Pas assez de crédits pour la requête                                                      |
| 502      | `MODEL_EMPTY_RESPONSE` | `server_error`          | Le modèle a terminé proprement sans aucun texte                                           |
| variable | code du fournisseur    | `server_error`          | Échec de génération en amont                                                              |

Deux cas sortent de cette enveloppe : les erreurs de `GET /models`, et les corps de requête rejetés par la validation (une `temperature` hors plage, par exemple) — les deux renvoient une forme d'erreur simple.

## Limites de débit et quotas \[#rate-limits-and-quotas]

Cette API n'a **ni limite de débit par clé, ni plafond de concurrence, ni quota de requêtes**. Deux choses seulement bornent votre usage :

| Borne                        | Valeur                                                                                                    |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
| Solde de crédits             | Vérifié avant chaque requête ; en cas d'échec, renvoie `insufficient_quota`                               |
| Fenêtre des modèles gratuits | 15 messages par tranche de 3 heures, par compte — ×3 en Pro (45), ×4 en Premium (60), ×5 en Ultimate (75) |

La fenêtre des modèles gratuits est partagée avec le chat web, les histoires, les romans et les bots — c'est une seule enveloppe par compte, pas une par surface. [Modèles gratuits →](https://reverie.im/fr/docs/reference/free-models)

Reverie n'envoie aucun webhook sortant ; il n'y a rien à quoi s'abonner pour être prévenu d'une fin de génération.

## Importer des personnages \[#importing-characters]

Un second endpoint, `POST /api/v1/characters/import`, crée un personnage à partir d'une fiche de personnage. Il exige une clé disposant de la portée d'import, qui n'est pas le type de clé créé par la page des réglages. [Clés API →](https://reverie.im/fr/docs/integrations/api-keys) et [Importer des personnages →](https://reverie.im/fr/docs/characters/import-characters)

## Voir aussi \[#related]

* [Clés API](https://reverie.im/fr/docs/integrations/api-keys) — créer, épingler, faire expirer et surveiller des clés
* [Modèles](https://reverie.im/fr/docs/reference/models) — IDs de modèle et multiplicateurs de crédits
* [Limites](https://reverie.im/fr/docs/reference/limits) — les autres plafonds du produit
* [Crédits](https://reverie.im/fr/docs/billing/credits) — comment les requêtes sont facturées
