# API abierta

> Un endpoint compatible con OpenAI para tus personajes.

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

Reverie expone un endpoint de Chat Completions compatible con OpenAI. Apunta cualquier cliente de OpenAI hacia él, pásale una clave API de Reverie y usa el campo `model` para nombrar un **personaje o escenario** en lugar de un LLM. Reverie guarda la conversación, las memorias y los resúmenes de su lado, así que cada petición solo necesita tu mensaje nuevo.

Cualquier cuenta con sesión iniciada puede usarlo. No hay nivel de suscripción ni lista de espera: solo necesitas una clave API, y ya está. [Crear una →](https://reverie.im/es/docs/integrations/api-keys)

## URL base y autenticación \[#base-url-and-auth]

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

**Ajustes → Más → Claves API** muestra la URL base exacta en la tarjeta **API Endpoint**, con un botón para copiarla.

> **Esta es una API de servidor.** Las peticiones de navegador desde otro origen están bloqueadas, así que un fetch desde tu propia página web fallará por muy correcta que sea la clave. Llámala desde un backend y mantén la clave fuera del código del cliente.

## Inicio rápido \[#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 ?? "");
}
```

**Ajustes → Más → Claves API** también tiene un constructor de peticiones que genera estos tres fragmentos con una de tus claves reales y un personaje real.

## El campo `model` nombra un personaje \[#the-model-field-names-a-character]

> **El nombre del personaje a secas no funciona.** `model: "Luna"` no busca un personaje llamado Luna. No coincide con nada, cae en el personaje por defecto de la clave o en tu chat más reciente, y recibes la respuesta de otro personaje sin ningún error. Usa siempre la forma `Nombre [idcorto]` que devuelve `GET /models`.

| Valor de `model`                                       | Quién responde                                                      |
| ------------------------------------------------------ | ------------------------------------------------------------------- |
| `Luna [abc12345]`                                      | El personaje o escenario cuyo ID termina en esos 8 caracteres       |
| Un ID completo de personaje o escenario                | Ese personaje o escenario                                           |
| Un ID de modelo de Reverie, p. ej. `deepseek-v4-flash` | Elige el **LLM**; el personaje sale de la clave o de tu último chat |
| Omitido                                                | El personaje fijado a la clave, si no tu chat más reciente          |

Detalles que deciden si un ID corto se resuelve:

* El `[...]` tiene que ir al **final** de la cadena.
* Un sufijo de 8 caracteres o menos solo se compara con personajes **con los que ya tienes un chat**, en la web o por la API. El ID corto de un personaje que nunca has abierto falla en silencio.
* La búsqueda de escenarios solo se ejecuta cuando la clave está fijada a un personaje. Con una clave global, un ID corto de escenario no puede resolverse nunca.
* Más de 8 caracteres se trata como un ID completo.

### Ver con qué puedes hablar \[#listing-what-you-can-talk-to]

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

Una clave **global** devuelve tus personajes recientes. Una clave **fijada a un personaje** devuelve los escenarios de ese personaje, o el propio personaje si no tiene ninguno. Cada entrada se ve así:

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

Copia `id` tal cual en `model`. Los errores de este endpoint usan una forma de error simple, no el envoltorio de OpenAI.

## Qué lee el cuerpo de la petición \[#what-the-request-body-reads]

Se leen cuatro campos. Todo lo demás se acepta y se descarta en silencio.

| Campo         | Tipo       | Por defecto                          | Notas                                                                   |
| ------------- | ---------- | ------------------------------------ | ----------------------------------------------------------------------- |
| `messages`    | array      | obligatorio                          | Ver abajo: solo se usa una parte                                        |
| `model`       | string     | opcional                             | Personaje, escenario o LLM, como arriba                                 |
| `stream`      | booleano   | **`true`**                           | El streaming es lo predeterminado, al contrario que en la API de OpenAI |
| `temperature` | número 0–2 | el ajuste del personaje, si no `0.8` | Los valores fuera de rango se rechazan                                  |

Se ignoran sin avisar: `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Cómo se trata `messages`:

* **Los mensajes `system` se descartan.** La personalidad y el comportamiento vienen de los campos del propio personaje, no de la petición. [Campos del prompt →](https://reverie.im/es/docs/characters/prompt-fields)
* **No hay soporte de visión.** El contenido puede ser una cadena o un array de partes, pero solo se leen las partes `text`; las partes de imagen se ignoran.
* Solo se añade a la conversación el \*\*último mensaje `user`\*\*. Los mensajes de usuario anteriores se ignoran.
* Los mensajes de asistente solo se usan para sincronizar el historial (abajo).
* Un último mensaje de usuario vacío o con solo espacios devuelve `missing_user_message`.

## Respuestas \[#responses]

Una respuesta sin streaming es un objeto `chat.completion` normal. `finish_reason` es siempre `stop` —las llamadas internas a herramientas nunca se exponen— y los contadores de `usage` están a cero, así que mide los tokens con las estadísticas de uso de la página de claves API y no con la respuesta.

Una respuesta en streaming es `text/event-stream`:

1. Fragmentos de contenido: objetos `chat.completion.chunk` con `delta.content`. \*&#x2A;No se envía un fragmento inicial `delta: {"role": "assistant"}`.*\*
2. Un fragmento de cierre, con `finish_reason` igual a `stop`, `length` o `content_filter`. Los cierres por llamada a herramienta se reportan como `stop`.
3. Un fragmento de uso con el array `choices` vacío.
4. `data: [DONE]`.

Si la generación falla a mitad del stream, el stream emite `data: {"error": {...}}` y luego `[DONE]`.

## Estado de la conversación \[#conversation-state]

Reverie guarda la conversación. Existe un chat por cada par de clave y personaje, aparece en la aplicación web junto a tus otros chats, y cada turno se construye con el prompt de sistema y el escenario del personaje, el canon de los libros del mundo, las memorias a largo plazo, los resúmenes que se van acumulando, el estilo de narración del personaje, la longitud de respuesta y los ajustes NSFW, un bloqueo de idioma tomado del idioma de tu cuenta, y todo el historial reciente que quepa en la ventana de contexto del modelo. Las herramientas de memoria se ejecutan cuando el modelo admite herramientas.

Como el servidor guarda el historial, no hace falta que lo vuelvas a enviar.

> **Enviar mensajes de asistente puede borrar historial.** Si tu array `messages` contiene mensajes de asistente, Reverie toma el último, lo busca entre los 20 mensajes guardados más recientes y, si lo encuentra, borra de forma permanente todos los mensajes creados después de él, junto con las memorias creadas a partir de ese punto. Si no encuentra nada, no borra nada. La longitud de tu array da igual. Para evitarlo del todo, envía solo el mensaje nuevo del usuario.

## Qué LLM responde \[#which-llm-answers]

Lo decide el personaje, no la petición, salvo que nombres un LLM. Precedencia, de menor a mayor: el modelo de chat por defecto, luego el ajuste de modelo del propio personaje, luego un ID de modelo de Reverie pasado como `model`, y por último la preferencia de modelo que fijaste para ese chat en la aplicación web, que gana a todas. [Modelos →](https://reverie.im/es/docs/reference/models)

## Errores \[#errors]

Los errores de `/chat/completions` usan el envoltorio de OpenAI: `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP  | `code`                 | `type`                  | Causa                                                                                       |
| ----- | ---------------------- | ----------------------- | ------------------------------------------------------------------------------------------- |
| 401   | `invalid_api_key`      | `invalid_request_error` | Falta `Authorization` o está mal formada, la clave es desconocida, o la clave está inactiva |
| 401   | `api_key_expired`      | `invalid_request_error` | La clave ha pasado su fecha de caducidad                                                    |
| 404   | `scenario_not_found`   | `invalid_request_error` | El ID de escenario se resolvió pero el escenario ya no existe                               |
| 404   | `character_not_found`  | `invalid_request_error` | El personaje no existe o fue borrado                                                        |
| 404   | `no_chat_history`      | `invalid_request_error` | Sin `model`, sin personaje fijado y sin chat previo al que recurrir                         |
| 400   | `missing_user_message` | `invalid_request_error` | No hay ningún mensaje `user` no vacío                                                       |
| 429   | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Ventana de modelos gratuitos agotada. `Retry-After` da los segundos de espera               |
| 429   | `insufficient_quota`   | `insufficient_quota`    | No hay créditos suficientes para la petición                                                |
| 502   | `MODEL_EMPTY_RESPONSE` | `server_error`          | El modelo terminó limpiamente sin texto                                                     |
| varía | código del proveedor   | `server_error`          | Fallo de generación aguas arriba                                                            |

Dos casos quedan fuera de ese envoltorio: los errores de `GET /models` y los cuerpos de petición rechazados por la validación (una `temperature` fuera de rango, por ejemplo). Ambos devuelven una forma de error simple.

## Límites de uso y cuotas \[#rate-limits-and-quotas]

Esta API **no tiene límite de peticiones por clave, ni tope de concurrencia, ni cuota de peticiones**. Solo dos cosas acotan tu uso:

| Cota                         | Valor                                                                                          |
| ---------------------------- | ---------------------------------------------------------------------------------------------- |
| Saldo de créditos            | Se comprueba antes de cada petición; si falla devuelve `insufficient_quota`                    |
| Ventana de modelos gratuitos | 15 mensajes cada 3 horas, por cuenta — ×3 en Pro (45), ×4 en Premium (60), ×5 en Ultimate (75) |

La ventana de modelos gratuitos se comparte con el chat web, las historias, las novelas y los bots: es una asignación por cuenta, no una por sitio. [Modelos gratuitos →](https://reverie.im/es/docs/reference/free-models)

Reverie no envía webhooks salientes; no hay nada a lo que suscribirse para recibir avisos de finalización.

## Importar personajes \[#importing-characters]

Un segundo endpoint, `POST /api/v1/characters/import`, crea un personaje a partir de una ficha de personaje. Necesita una clave con permiso de importación, que no es el tipo de clave que crea la página de ajustes. [Claves API →](https://reverie.im/es/docs/integrations/api-keys) e [Importar personajes →](https://reverie.im/es/docs/characters/import-characters)

## Relacionado \[#related]

* [Claves API](https://reverie.im/es/docs/integrations/api-keys) — crear, fijar, caducar y vigilar claves
* [Modelos](https://reverie.im/es/docs/reference/models) — IDs de modelo y multiplicadores de créditos
* [Límites](https://reverie.im/es/docs/reference/limits) — los demás topes del producto
* [Créditos](https://reverie.im/es/docs/billing/credits) — cómo se cobran las peticiones
