API pública
El helpdesk expone una única API pública: un endpoint GraphQL. Toda operación del esquema es accesible fuera del navegador con un token de acceso personal (Personal Access Token, PAT).
Esta página es el contrato: qué es estable, cómo autenticarse, qué conceden los ámbitos y qué forma tienen los errores. La CLI hdmx se construye sobre ella, y el versionado de la API explica cómo evoluciona esta superficie.
El endpoint
POST https://<your-host>/backend/<subdomain>/api/<version>/graphql
<subdomain>identifica tu cuenta (el mismo identificador con el que inicias sesión).<version>es una versión con fecha de la API, como2026-07— consulta versionado de la API. También puedes omitir el segmento de versión y llamar a…/backend/<subdomain>/graphql; entonces la petición la atiende la versión más antigua soportada y cada respuesta te indica qué versión respondió.
Autenticación
Envía un token de acceso personal como credencial Bearer:
Authorization: Bearer hdmx_<random>
Un PAT es de larga duración (con caducidad obligatoria), está limitado por ámbitos, restringido por IP y es revocable. Está ligado a una sola cuenta: presentar un token al subdominio de otra cuenta se rechaza con HTTP 401.
Crear un token
Crea y gestiona los tokens tú mismo en la aplicación de agente, en Settings → API tokens:
- Haz clic en New token.
- Dale un nombre que reconozcas más adelante.
- Elige una caducidad (hasta 365 días; no existe la opción «nunca»).
- Define una política de acceso: activa exactamente los recursos que este token necesita, en lectura o en lectura y escritura. Por defecto no hay acceso a nada.
- Añade al menos una dirección IP o CIDR a la lista de permitidas (obligatorio; consulta Lista de IP permitidas). El formulario puede añadir tu IP actual por ti.
- Revisa y crea. El token completo se muestra exactamente una vez: cópialo de inmediato. Solo se almacena un hash, así que nunca puede volver a mostrarse; si lo pierdes, rota el token para obtener uno nuevo.
Más adelante puedes editar la política de acceso y la lista de permitidas de un token, rotarlo (emitir un secreto nuevo mientras el antiguo sigue funcionando durante un breve periodo de gracia, para poder cambiar sin caídas) y revocarlo. Cada token muestra cuándo y desde dónde se usó por última vez, además de un registro de actividad reciente.
Ámbitos
El acceso es de grano grueso y está organizado por familias de recursos. Un token lleva un conjunto fijo de ámbitos; cada operación de nivel superior comprueba uno.
| Ámbito | Concede |
|---|---|
tickets:read | Leer tickets, mensajes, borradores, historial, adjuntos, informes |
tickets:write | Crear / actualizar / eliminar tickets, publicar mensajes, subir adjuntos. Implica tickets:read |
chat:read | Leer chats, conversaciones, mensajes, sesiones |
chat:write | Enviar mensajes de agente, unirse / salir / cerrar / reabrir conversaciones. Implica chat:read |
customers:read | Leer fichas de clientes |
customers:write | Crear / actualizar / fusionar fichas de clientes. Implica customers:read |
settings:read | Leer la configuración de la cuenta (departamentos, estados, prioridades, buzones — sin secretos) |
Los campos de credenciales de los buzones (usuarios, contraseñas y hosts de IMAP/SMTP) nunca se devuelven a un token, sea cual sea el ámbito: esos secretos pertenecen a tu proveedor de correo y quedan fuera del alcance de la API pública.
Taxonomía de errores
Las respuestas GraphQL usan errors[].extensions.code:
| Código | Significado | HTTP |
|---|---|---|
SCOPE_DENIED | Al token le falta el ámbito requerido. extensions.valid_values enumera el ámbito o ámbitos que satisfarían la operación | 200 |
RATE_LIMITED | Se agotó el presupuesto de peticiones por token. extensions.retryAfter son los segundos que faltan para el reinicio, y la cabecera Retry-After lleva el mismo número | 429 |
INVALID_API_TOKEN | Token no encontrado, mal formado o inutilizable por otro motivo | 200 |
Los tokens revocados, los caducados, las discrepancias entre cuentas y los rechazos por la lista de IP permitidas se rechazan antes de ejecutar la consulta y se manifiestan como HTTP 401 sin cuerpo GraphQL. Trata un 401 en una petición con token como «este token ya no es válido para esta petición: revisa su caducidad, sus ámbitos y su lista de IP permitidas».
Límites de tasa
Cada petición con token lleva cabeceras:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 96
X-RateLimit-Reset: 1715692800
El presupuesto por defecto es de 120 peticiones por minuto y token. Cada petición cuesta 1, tanto si lee como si escribe. Superarlo devuelve HTTP 429 con una cabecera Retry-After y extensions.code = "RATE_LIMITED"; un cliente bien educado espera hasta el momento del reinicio.
Lista de IP permitidas
Todo token de autoservicio debe llevar al menos una IP o CIDR: no existen tokens «para cualquier IP». La IP de origen de cada petición se compara con la lista del token; si no coincide, se rechaza con HTTP 401 y extensions.sub_code = "ip_not_allowed".
- Se aceptan IPv4, IPv6 y rangos CIDR. Usa
/32(IPv4) o/128(IPv6) para un solo host. - Los rangos se validan y normalizan al guardarlos.
- La lista de permitidas se puede editar tras la creación; editarla no cambia el secreto.
Usa un token desde una salida estable: un runner de CI, una tarea programada, un NAT de oficina fijo o tus propios servidores en un rango de IP conocido. Un token filtrado es inútil desde cualquier lugar fuera de su lista de permitidas.
Actividad del token
Cada petición autenticada que hace un token queda registrada: la hora, el nombre de la operación, la IP de origen, el resultado (éxito, error, límite de tasa, ámbito denegado, revocado o caducado) y la latencia de ida y vuelta. Este es el rastro que conviene revisar si un token se comporta de forma inesperada.
Versionado y obsolescencia
La API se versiona con versiones con fecha YYYY-MM. Fija una en la URL y se mantendrá estable durante al menos 12 meses; las obsolescencias se anuncian en banda antes de que desaparezca nada de lo que uses. Consulta Versionado de la API para la política completa.
Descubrimiento del esquema
El esquema se autodescribe: usa la introspección GraphQL estándar contra el endpoint versionado para generar tipos y explorar la superficie. El GraphQL Playground interactivo está disponible en …/backend/<subdomain>/playground.
Inicio rápido con curl
Estos ejemplos asumen el host helpdesk.example.com, el subdominio acme, la versión 2026-07 y un token en $TOKEN.
Leer el usuario actual (cualquier ámbito)
curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"{ currentUser { id email firstname lastname } }"}'
Listar tickets recientes (tickets:read)
curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query ($first: Int!) {
ticketList(first: $first) {
edges { node { code subject status { name } updatedAt } }
}
}",
"variables": { "first": 10 }
}'
Publicar una respuesta pública (tickets:write)
curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ($input: SaveTicketInput!) {
saveTicket(input: $input) {
ticket { code }
error { code message }
}
}",
"variables": {
"input": {
"id": "TICKET-UUID-HERE",
"message": "Thanks — fixing this now.",
"messageType": "PUBLIC"
}
}
}'
Para el día a día, la CLI hdmx envuelve toda esta superficie tras comandos ergonómicos.