Esta página documenta la superficie viva de /api/v1/**, incluidas las rutas del companion de escritorio y los endpoints heredados que siguen siendo accesibles pero no deben usarse en integraciones nuevas.
URL base
| Entorno | URL |
| ---------- | --------------------------------- |
| Producción | https://www.devspeak.dev/api/v1 |
El documento OpenAPI legible por máquinas se sirve en [/openapi.json](/openapi.json).
| Familia de rutas | Mecanismo de autenticación | Notas |
| --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------- |
| GET /api/v1/health | Ninguno | Health check público |
| GET /api/v1/me, GET /api/v1/auth/confirm, GET /api/v1/history, POST /api/v1/translate, POST /api/v1/optimize, POST /api/v1/refine | x-api-key o token de ID Bearer | translate, optimize y refine también validan scopes |
| POST /api/v1/auth/session-key | token de ID Bearer | Intercambia una sesión iniciada por una API key temporal dsk_sess_ |
| POST, GET, DELETE /api/v1/user/config/providers/* | token de ID Bearer o session key | También exige la feature customProvider |
| POST /api/v1/desktop/session | token de ID Bearer o session key | Crea un token de sesión para escritorio |
| Resto de /api/v1/desktop/* | Bearer de sesión de escritorio | Requiere una sesión de escritorio (/metadata y /download son públicos) |
Un token de ID Bearer es el token de corta duración que se emite al iniciar sesión en DevSpeak con Google, GitHub o AgentID. Envíalo como Authorization: Bearer .
| Scope | Significado |
| ----------------- | --------------------------------------------------------------------------------------- |
| optimize:write | Requerido por POST /api/v1/translate, POST /api/v1/optimize y POST /api/v1/refine |
| translate:write | Reservado para uso futuro |
| history:read | Reservado para uso futuro |
| notes:write | Requerido por POST /api/v1/notes/:noteId/patch |
| Scope | Significado |
| ------------------------ | ------------------------------------------------------------ |
| desktop:projects:read | Leer proyectos registrados del cliente de escritorio |
| desktop:projects:write | Crear proyectos, reconciliar manifiestos e inyectar contexto |
| desktop:notes:read | Listar notas |
| desktop:notes:write | Editar una nota |
| desktop:sync:read | Consultar el feed heredado de eventos de sincronización |
| Alcance | Límite | Ventana |
| ----------------------------------------------------------------- | ----------------- | ----------------------- |
| Por API key | 100 solicitudes | 1 minuto |
| Global por IP | 180 solicitudes | 15 minutos |
| Creación de sesiones de escritorio y rutas de escritura intensiva | strictLimiter | Aplicado en el servidor |
Las respuestas pueden incluir:
``text
RateLimit-Limit: 100
RateLimit-Remaining: 97
RateLimit-Reset: 1711296060
`Inventario de endpoints
Rutas principales
| Método | Ruta | Auth | Estado | Resumen |
| -------- | --------------------------------------- | ------------------------- | --------- | ------------------------------------------------------------ |
| GET | /api/v1/health | Ninguna | Soportado | Health check público |
| GET | /api/v1/me | API key o token de ID | Soportado | Identidad, tier, features, cuotas y uso |
| GET | /api/v1/me/entitlements | API key o token de ID | Soportado | Token de entitlements firmado para caché en el cliente |
| GET | /api/v1/auth/confirm | API key o token de ID | Soportado | Valida una session key activa o una sesión iniciada |
| POST | /api/v1/auth/session-key | token de ID | Soportado | Crea una API key efímera con los scopes solicitados |
| POST | /api/v1/auth/session-renew | Session key | Soportado | Intercambia la session key actual por una sucesora |
| POST | /api/v1/auth/session-revoke | Session key | Soportado | Revoca la session key presentada |
| GET | /api/v1/history | API key o token de ID | Soportado | Historial paginado de traducciones |
| POST | /api/v1/translate | API key o token de ID | Soportado | Pipeline completo de traducción de la etapa 2 |
| POST | /api/v1/optimize | API key o token de ID | Soportado | Optimización léxica estilo DeepL Write de la etapa 1 |
| POST | /api/v1/optimize/summarize | API key o token de ID | Soportado | Condensa entradas demasiado largas (hasta 15,000 caracteres) |
| POST | /api/v1/refine | API key o token de ID | Soportado | Refinamiento iterativo de la etapa 3 |
| POST | /api/v1/detect-language | API key o token de ID | Soportado | Detecta el idioma de una entrada |
| POST | /api/v1/notes/:noteId/patch | API key o token de ID | Soportado | Edición quirúrgica de una nota; requiere notes:write |
| GET | /api/v1/user/config/providers/current | token de ID o session key | Soportado | Obtiene la configuración activa del proveedor personalizado |
| POST | /api/v1/user/config/providers/test | token de ID o session key | Soportado | Valida un borrador del proveedor sin guardarlo |
| POST | /api/v1/user/config/providers | token de ID o session key | Soportado | Guarda una configuración de proveedor personalizado |
| DELETE | /api/v1/user/config/providers/current | token de ID o session key | Soportado | Elimina la configuración activa del proveedor |Rutas del companion de escritorio
| Método | Ruta | Auth | Estado | Resumen |
| ------- | -------------------------------- | ------------------------- | --------- | ---------------------------------------------------------------------------------------------- |
| GET | /api/v1/desktop/appcast.xml | Ninguna | Soportado | Feed de actualizaciones Sparkle de la app de macOS |
| GET | /api/v1/desktop/metadata | Ninguna | Soportado | Metadatos de la build de escritorio actual |
| GET | /api/v1/desktop/download | Ninguna | Soportado | URL firmada de descarga de la build de escritorio actual |
| POST | /api/v1/desktop/session | token de ID o session key | Soportado | Crea o renueva un token de sesión de escritorio |
| GET | /api/v1/desktop/projects | Sesión de escritorio | Soportado | Lista proyectos registrados en escritorio |
| POST | /api/v1/desktop/projects | Sesión de escritorio | Soportado | Crea o actualiza un proyecto de escritorio |
| POST | /api/v1/desktop/projects/sync | Sesión de escritorio | Soportado | Reconciliación de un manifiesto SHA-256 contra el estado del servidor |
| GET | /api/v1/desktop/sync | Sesión de escritorio | Legado | Consulta eventos de sync. El inventario lo marca como huérfano; no lo uses en clientes nuevos. |
| POST | /api/v1/desktop/context/inject | Sesión de escritorio | Soportado | Construye un workspaceContext compacto a partir de chunks locales |
| GET | /api/v1/desktop/notes | Sesión de escritorio | Soportado | Lista las notas del usuario |
| PATCH | /api/v1/desktop/notes/:noteId | Sesión de escritorio | Soportado | Edita una nota |GET /api/v1/healthEsquemas principales de petición y respuesta
No requiere autenticación.
`json
{
"success": true,
"data": {
"status": "ok",
"version": "v1",
"timestamp": "2026-04-13T12:00:00.000Z"
}
}
`GET /api/v1/me
Devuelve el contexto efectivo del plan y del uso para el caller autenticado.
`json
{
"success": true,
"data": {
"userId": "abc123",
"tier": "DEVELOPER",
"features": ["apiAccess", "iterativeRefinement", "customProvider"],
"limits": {
"managedTokensPerMonth": 10000000,
"maxApiKeys": 3
},
"usage": {
"refinementCount": 12,
"currentPeriod": "2026-04"
},
"quotas": {
"managedTokens": 10000000,
"apiKeys": 3,
"managedTokensUnlimited": false,
"apiKeysUnlimited": false
}
}
}
`GET /api/v1/auth/confirm
Confirma que la API key o la sesión iniciada (token de ID Bearer) suministrada sigue asociada a un usuario activo.
`json
{
"success": true,
"data": {
"userId": "abc123",
"confirmed": true
}
}
`POST /api/v1/auth/session-key
Requiere un token de ID Bearer.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ------------------ | ---------- | --------- | ----------------------------- |
| scopes | string[] | No | El valor predeterminado es [ |
| "optimize:write"] |
| label | string | No | Máximo 100 caracteres |
Respuesta
`json
{
"success": true,
"data": {
"key": "dsk_sess_a1b2c3d4e5f6...",
"expiresAt": "2026-04-14T12:00:00.000Z",
"scopes": ["optimize:write"]
}
}
`GET /api/v1/history
Parámetros de consulta
| Parámetro | Tipo | Requerido | Predeterminado | Notas |
| --------- | -------- | --------- | -------------- | ----------------------------------- |
| limit | number | No | 50 | Ajustado al rango 1..200 |
| offset | number | No | 0 | Offset de paginación basado en cero |
Respuesta
`json
{
"success": true,
"data": {
"items": [
{
"id": "translation_123",
"inputText": "We need a login page that works with Google.",
"output": "## Technical Specification...",
"audience": "Senior Dev",
"context": "Backend",
"format": "Technical Spec",
"tone": 75,
"wordCount": 847,
"latencyMs": 3200,
"model": "
"provider": "
"createdAt": "2026-04-13T12:00:00.000Z"
}
],
"total": 1,
"offset": 0,
"limit": 50
}
}
`POST /api/v1/translate
Generación completa de la etapa 2. Requiere optimize:write y la feature apiAccess.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| -------------------- | --------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| input | string | Sí | 10..10000 caracteres |
| audience | enum | Sí | Junior Dev, Senior Dev, Tech Lead, SRE, Data Engineer |
| context | enum | Sí | Backend, Frontend, Mobile, Data/ML, DevOps |
| format | enum | Sí | Technical Spec, Jira Tickets, API Design, RFC, Data Model, Prompt, Optimize |
| tone | integer | Sí | 0..100 |
| customInstructions | string | No | Máximo 10000 caracteres |
| workspaceContext | string | No | Máximo 150000 caracteres |
| translationId | string | No | Máximo 200 caracteres, ^[A-Za-z0-9_-]+$ |
| webSearch | boolean | No | Fundamentación RAG con recuperación web en tiempo real. Por defecto false |
| responseFormat | enum | No | markdown (por defecto) o xml para un documento legible por máquina |
| managedModel | string | No | Fija un modelo gestionado. Se rechaza si no está en la lista permitida del servidor. Omítelo para que el router LLM elija según la solicitud |
`bash
curl -X POST https://www.devspeak.dev/api/v1/translate \
-H "Content-Type: application/json" \
-H "x-api-key: $DEVSPEAK_API_KEY" \
-d '{
"input": "We need a login page that works with Google and saves user data",
"audience": "Senior Dev",
"context": "Backend",
"format": "Technical Spec",
"tone": 75,
"customInstructions": "Call out persistence, observability, and rollout concerns."
}'
`
Envelope de respuesta
`json
{
"success": true,
"data": {
"output": "## Technical Specification: User Authentication System\n\n### 1. Overview\n...",
"metadata": {
"wordCount": 847,
"latencyMs": 3200,
"model": "
"provider": "
"credentialSource": "managed",
"endpointHost": null
}
}
}
`POST /api/v1/optimize
Optimización léxica de la etapa 1. Requiere optimize:write. Este endpoint es determinista y libre de contexto de tarea: solo acepta el texto de entrada, la audiencia, el contexto y un managedModel opcional. A diferencia de /api/v1/translate, no genera un documento técnico formateado y no acepta campos de la etapa 2 como format, tone, customInstructions, adjuntos o contextProjectId — los campos no soportados se registran y descartan en lugar de rechazarse. Las instrucciones personalizadas a nivel de cuenta almacenadas en tu perfil siguen aplicándose. Los resultados nunca se persisten en el historial de traducciones.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| -------------- | -------- | --------- | ---------------------------------------------------------------------------- |
| input | string | Sí | 10..10000 caracteres |
| audience | enum | Sí | Mismo enum que /translate |
| context | enum | Sí | Mismo enum que /translate |
| managedModel | string | No | Modelo gestionado permitido (opcional). Omítelo para que el router LLM elija |
`bash
curl -X POST https://www.devspeak.dev/api/v1/optimize \
-H "Content-Type: application/json" \
-H "x-api-key: $DEVSPEAK_API_KEY" \
-d '{
"input": "pls make this spec more professional and clearer",
"audience": "Senior Dev",
"context": "Backend"
}'
`
El envelope de respuesta coincide con /api/v1/translate y devuelve el texto optimizado en data.output.POST /api/v1/refine
Refinamiento de la etapa 3. Requiere optimize:write y la feature iterativeRefinement.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ------------------ | --------- | --------- | ----------------------------------------------------------------------------- |
| originalInput | string | No | El servidor usa "" por defecto; máximo 10000 caracteres |
| previousOutput | string | Sí | 1..50000 caracteres |
| feedback | string | Sí | 1..5000 caracteres |
| audience | enum | Sí | Mismo enum que /translate |
| context | enum | Sí | Mismo enum que /translate |
| format | enum | Sí | Mismo enum que /translate |
| tone | integer | Sí | 0..100 |
| workspaceContext | string | No | Máximo 150000 caracteres |
| translationId | string | No | Máximo 200 caracteres |
| webSearch | boolean | No | Fundamentación RAG. Por defecto false |
| responseFormat | enum | No | markdown (por defecto) o xml |
| managedModel | string | No | Modelo gestionado de la lista permitida. Omítelo para que el router LLM elija |
`bash
curl -X POST https://www.devspeak.dev/api/v1/refine \
-H "Content-Type: application/json" \
-H "x-api-key: $DEVSPEAK_API_KEY" \
-d '{
"originalInput": "We need a login page that works with Google and saves user data",
"previousOutput": "## Technical Specification...",
"feedback": "Add a section on rate limiting and explicit error codes.",
"audience": "Senior Dev",
"context": "Backend",
"format": "Technical Spec",
"tone": 75
}'
`
Las respuestas exitosas usan el mismo envelope que /translate, con metadata.isOutOfScope cuando el feedback de refinamiento se rechaza por ser ajeno al documento.Rutas de configuración de proveedor
Estas rutas aceptan token de ID Bearer o una session key y requieren la feature customProvider.GET /api/v1/user/config/providers/current
Devuelve la configuración actual del proveedor o null si no hay ninguna configurada.
Cuando no existe un proveedor personalizado guardado, la ruta responde con:
`json
{
"success": true,
"data": null,
"configured": false
}
`
`json
{
"success": true,
"data": {
"providerType": "gemini",
"providerName": "Gemini",
"apiEndpoint": null,
"metadata": {
"model": "gemini-3-flash-preview",
"label": "Gemini",
"keyPreview": "AIza...1234",
"endpointHost": null
},
"enabled": true,
"updatedAt": "2026-04-13T12:00:00.000Z",
"lastValidatedAt": "2026-04-13T12:00:00.000Z",
"status": "active",
"validationMessage": null
}
}
`POST /api/v1/user/config/providers/testPOST /api/v1/user/config/providers
Ambos endpoints aceptan el mismo esquema de borrador:
| Campo | Tipo | Requerido | Notas |
| ----------------- | --------- | ----------- | ---------------------------------------------------- |
| providerType | enum | Sí | gemini, openai, anthropic, openai-compatible |
| providerName | string | Sí | 1..100 caracteres |
| apiKey | string | Condicional | Obligatorio salvo que isExistingKey sea true |
| isExistingKey | boolean | No | Reutiliza la clave cifrada ya guardada |
| baseURL | string | Condicional | Obligatorio para openai-compatible |
| modelIdentifier | string | No | 1..120 caracteres |
/test valida un borrador sin persistirlo. /providers valida y guarda la configuración. Ambos responden con el mismo envelope de configuración mostrado arriba.DELETE /api/v1/user/config/providers/current
Elimina la configuración activa del proveedor.
`json
{
"success": true,
"data": null
}
`POST /api/v1/desktop/sessionRutas del companion de escritorio
Crea un token de sesión de escritorio a partir de una petición autenticada con un token de ID Bearer o con una session key.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ------------- | -------- | --------- | -------------------------------------------------------- |
| deviceId | string | Sí | 1..128, ^[A-Za-z0-9._:-]+$ |
| deviceLabel | string | Sí | 1..120 caracteres |
| runtime | enum | No | electron, tauri, unknown; predeterminado unknown |
Respuesta
`json
{
"success": true,
"data": {
"token": "desktop-session-token",
"expiresInSeconds": 900,
"scopes": [
"desktop:projects:read",
"desktop:projects:write",
"desktop:notes:read",
"desktop:notes:write",
"desktop:sync:read"
],
"device": {
"deviceId": "desktop-device-1",
"deviceLabel": "MacBook Pro",
"platform": "desktop-app",
"runtime": "electron",
"lastSeenAt": "2026-04-10T12:00:00.000Z"
}
}
}
`GET /api/v1/desktop/projects
Devuelve un array de proyectos registrados para la sesión de escritorio autenticada.
`json
{
"success": true,
"data": [
{
"projectId": "project-1",
"name": "Monorepo",
"rootPath": "/Users/dev/projects/monorepo",
"createdAt": "2026-04-10T11:00:00.000Z",
"updatedAt": "2026-04-10T12:00:00.000Z",
"lastSyncedAt": "2026-04-10T12:00:00.000Z",
"lastSyncedByDeviceId": "desktop-device-1"
}
]
}
`POST /api/v1/desktop/projects
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ----------- | -------- | --------- | ------------------------------------------------ |
| projectId | string | Sí | 1..128, formato de identificador de escritorio |
| name | string | Sí | 1..128 caracteres |
| rootPath | string | Sí | 1..2048, bloquea traversal de rutas |
Devuelve el proyecto actualizado y emite un evento de sync en el servidor.
`json
{
"success": true,
"data": {
"projectId": "project-1",
"name": "Monorepo",
"rootPath": "/Users/dev/projects/monorepo",
"createdAt": "2026-04-10T11:00:00.000Z",
"updatedAt": "2026-04-10T12:00:00.000Z",
"lastSyncedAt": "2026-04-10T12:00:00.000Z",
"lastSyncedByDeviceId": "desktop-device-1"
}
}
`POST /api/v1/desktop/projects/sync
Endpoint de reconciliación de manifiestos.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ----------- | -------- | --------- | --------------------------- |
| projectId | string | Sí | Identificador de escritorio |
| files | array | Sí | Máximo 10000 entradas |
Cada elemento de files[] admite:
| Campo | Tipo | Requerido | Notas |
| ------------ | --------- | --------- | -------------------------------------- |
| path | string | Sí | Máximo 1024; traversal bloqueado |
| hash | string | Sí | SHA-256 en minúsculas de 64 caracteres |
| sizeBytes | integer | No | 0..50000000 |
| modifiedAt | string | No | Fecha ISO 8601 |
Las respuestas devuelven un delta con listas de subida, borrado y archivos sin cambios.
`json
{
"success": true,
"data": {
"manifestId": "user-123-project-1-1713000000000",
"toUpload": ["app/main.py", "app/routes/orders.py"],
"toDelete": ["app/deprecated.py"],
"unchanged": ["pyproject.toml"],
"totalFiles": 3
}
}
`POST /api/v1/desktop/context/inject
Construye un workspaceContext compacto a partir de chunks de archivos locales.
Cuerpo de la petición
| Campo | Tipo | Requerido | Notas |
| ----------- | -------- | --------- | --------------------------------------------- |
| projectId | string | Sí | Identificador de escritorio |
| label | string | No | Máximo 200 caracteres |
| query | string | No | Máximo 32000 caracteres — ver ranking abajo |
| chunks | array | Sí | 1..200 elementos |
Envía en query el texto de entrada de la traducción pendiente. Los chunks se
ordenan según su relevancia — por ruta, nombre de archivo y símbolos extraídos —
para que los archivos relevantes sobrevivan al límite de 150,000 caracteres de
contexto. Si se omite, el ensamblado usa el orden en que se enviaron los chunks,
lo que descarta en silencio los últimos en llegar.
Cada elemento de chunks[] admite:
| Campo | Tipo | Requerido | Notas |
| --------- | ---------- | --------- | ------------------------ |
| path | string | Sí | Máximo 1024 caracteres |
| content | string | Sí | Máximo 8192 caracteres |
| symbols | string[] | No | Máximo 100 entradas |
`json
{
"success": true,
"data": {
"contextId": "ctx-project-1-1713000000000",
"contextText": "# Project Context: project-1\n# Source files: 2\n...",
"tokenEstimate": 742,
"chunkCount": 2,
"includedCount": 2
}
}
`
includedCount indica cuántos chunks entraron en el límite. Un valor menor que
chunkCount significa que se descartó contexto.GET /api/v1/desktop/sync
Endpoint heredado de polling de sincronización. No lo uses para integraciones nuevas.
Parámetros de consulta
| Parámetro | Tipo | Requerido | Notas |
| ----------- | -------- | --------- | --------------------------------- |
| projectId | string | Sí | Identificador de escritorio |
| after | string | No | Cursor ISO 8601 |
| limit | number | No | Predeterminado 50, máximo 100 |
El inventario marca esta ruta como huérfana. Sigue disponible por compatibilidad, pero los clientes de escritorio nuevos deben usar POST /api/v1/desktop/projects/sync.
`json
{
"success": true,
"data": {
"items": [
{
"eventId": "event-1",
"eventType": "translation.upserted",
"userId": "user-123",
"occurredAt": "2026-04-10T12:30:00.000Z",
"source": "api-v1",
"projectId": "project-1",
"entityType": "translation",
"entityId": "translation-1",
"payload": {
"translationId": "translation-1"
}
}
],
"nextCursor": "2026-04-10T12:30:00.000Z",
"serverTime": "2026-04-10T12:30:05.000Z"
}
}
`POST /api/v1/optimize-inputRutas heredadas y en desuso
Devuelve 308 Permanent Redirect hacia /api/v1/optimize. El sunset actual en el inventario es 2026-10-01.POST /api/v1/user/config/keys
Ruta heredada de BYOK. Duplica el flujo de configuración de proveedores y está protegida por el mismo entitlement customProvider. No construyas integraciones nuevas sobre este endpoint.Envelope común de errores
`json
{
"success": false,
"error": "Mensaje de error legible para humanos",
"error_code": "ERR_VALIDATION_FAILED",
"details": []
}
`
| Estado | Significado |
| ------ | -------------------------------------------- |
| 400 | Fallo de validación |
| 401 | Credenciales ausentes, inválidas o expiradas |
| 403 | Faltan scopes, acceso a features o cuota |
| 422 | Fallo en la validación del proveedor |
| 429 | Límite de tasa excedido |
| 500 | Error interno del servidor |
| 504 | Timeout del upstream |Notas sobre la CLI y el render de rutas
y /docs/cli-guide` mediante registros MDX explícitos, de modo que estas páginas renderizan igual en local, staging y producción.