API REST
Lea y escriba sus monitores, lea y actualice incidentes, y suba source maps. Todo esto usa las mismas comprobaciones de permisos y el mismo filtro de aislamiento entre clientes que el panel — no hay una implementación aparte para la API que pueda desviarse de él.
Incluida en todos los planes, también en el gratuito. No hay complemento que comprar ni nivel que la desbloquee.
URL base
https://vitrinaengine.com/api/v1Descripción legible por máquinas
/openapi.json es un documento OpenAPI 3.1 que cubre todas las rutas de esta página. Apunte hacia él un generador de clientes, o entrégueselo a un agente que deba llamar a esta API sin que nadie se la explique.
Se genera a partir del servicio en lugar de escribirse a su lado: las rutas salen de la superficie que la propia API publica en GET /, las formas y su prosa de los mismos archivos .proto de /api/proto, y los límites de uso del código que los aplica. La compilación falla cuando el documento y la API discrepan, así que describe lo que se sirve y no lo que era cierto la última vez que alguien lo editó.
Describe las formas. Los motivos están en esta página — que un id de otra organización responde 404, que config nunca se devuelve — y eso no lo escribe ningún generador.
Para agentes: MCP
https://vitrinaengine.com/mcp es un servidor Model Context Protocol. Añádalo a un cliente MCP con una clave de API como token bearer y un agente podrá leer sus monitores, incidentes, errores y analíticas — y crear, modificar y eliminar monitores — sin que nadie le explique cómo funciona esta API.
{
"mcpServers": {
"vitrina-engine": {
"type": "http",
"url": "https://vitrinaengine.com/mcp",
"headers": { "Authorization": "Bearer vte_your_key_here" }
}
}
}Lee todo y escribe tres cosas. Cada operación GET de esta página es una herramienta, y también lo son POST /monitors, PATCH /monitors/{id} y DELETE /monitors/{id}. No hay ninguna otra escritura al alcance — ni un espacio de trabajo, ni un miembro, ni una clave de API, ni una página de estado, ni su cuenta — porque no existe herramienta para ninguna de ellas, y la lista de las que sí están permitidas son tres líneas que alguien tiene que añadir a propósito.
Una clave que no puede escribir sigue siendo rechazada. Una llamada a una herramienta es la misma petición que haría la clave directamente, con la misma comprobación de permisos y el mismo filtro de inquilino: un agente con una clave de solo lectura lee. Déle una, salvo que quiera que cambie su monitorización — y cuente con que un cliente le pregunte antes de borrar: al eliminar un monitor se va con él su historial y no hay vuelta atrás. Para callar un monitor sin perderlo, páuselo con PATCH.
Como es la misma petición, ve exactamente lo que ve la clave, escribe la misma entrada en el registro de auditoría que el panel y cuenta contra el mismo límite de uso, dos veces: una por la llamada y otra por la petición que contiene. Una escritura consume el límite de escritura.
Conviene saber una cosa antes de que un agente edite un monitor: config se reemplaza entero, no se fusiona. Lea primero el monitor, cambie ese campo y devuelva el objeto completo. Una configuración parcial descarta en silencio las cabeceras y las credenciales de las que depende la comprobación, y la deja funcionando.
Autenticación
Cree una clave en Ajustes → Claves de API y envíela como token bearer. La clave se muestra una sola vez, al crearla, y se guarda solo como hash — si la pierde, cree otra.
curl https://vitrinaengine.com/api/v1/summary \
-H "Authorization: Bearer vte_your_key_here"Una clave nunca otorga más de lo que tenía quien la creó. Está ligada a su membresía, así que lleva su rol: una clave creada por alguien con un rol de solo lectura no puede escribir, envíe lo que envíe. Una clave también puede confinarse a un solo espacio de trabajo, y en ese caso cada respuesta se filtra a ese espacio y lo que quede fuera no existe para esa clave.
Quitar a alguien de su organización revoca las claves que creó, en la misma operación. Revocar el acceso tiene que llevarse las credenciales con él, o la persona conserva una que funciona.
Convenciones
Toda respuesta correcta es un objeto JSON con una propiedad data. Todo fallo es un objeto JSON con una propiedad error que contiene una frase pensada para una persona.
{ "data": { "id": "8f14e45f-…", "name": "Marketing site" } }
{ "error": "This key cannot create monitors." }Las respuestas se envían con Cache-Control: private, no-store. Son datos propios de una clave sobre un origen compartido y no deben quedar guardados en ningún proxy.
Protobuf y gzip
Todos los endpoints bajo /api/v1 hablan también Protocol Buffers. Con Accept: application/x-protobuf la respuesta llega en protobuf; si envía un body en protobuf con Content-Type: application/x-protobuf, la respuesta vuelve en el mismo formato. Sin ninguno de los dos, es JSON, igual que siempre.
curl https://vitrinaengine.com/api/v1/monitors \
-H "Authorization: Bearer vte_your_key_here" \
-H "Accept: application/x-protobuf" \
--compressed -o monitors.pbLos mensajes están publicados: /api/proto enumera todos los archivos. Descárguelos conservando sus rutas y apunte protoc -I a ese directorio. Tres cosas difieren de lo que se esperaría en protobuf: un campo que puede estar vacío es null en JSON y está ausente en protobuf; algunos campos cuya forma varía —como el config de un monitor o de un canal— son documentos JSON dentro de un string; y StringList envuelve una lista que a su vez puede ser null.
Gzip funciona en ambos sentidos: Accept-Encoding: gzip para las respuestas y Content-Encoding: gzip para las peticiones. Como dos clientes pueden recibir ahora bytes distintos de la misma URL, todas las respuestas llevan Vary: Accept, Content-Type.
Códigos de estado
| Código | Significa |
|---|---|
200 | Todo bien. 201 cuando se creó algo. |
400 | El cuerpo no era JSON, falta un campo, o no se pidió ningún cambio. |
401 | Sin clave, o con una que no es válida. Deliberadamente nunca dice cuál de las dos — un mensaje que las distinguiera sería una forma de probar claves. |
403 | Una clave válida sin permiso para esta acción. El mensaje lo nombra. |
404 | No existe ese registro para usted. Vea más abajo. |
413 | Un source map por encima del límite de tamaño. |
429 | Superó un límite de peticiones. Lleva Retry-After. Vea más abajo. |
Códigos de rechazo
Todo cuerpo que no sea 2xx lleva un code junto a la frase — not_found, limit_reached, rate_limited — y ese es el campo sobre el que ramificar. La cadena error es prosa para alguien que lee un registro y puede reescribirse en cualquier momento; el código es estable. Cuando la frase nombra un valor, vars lleva esos valores como cadenas, de modo que puedas colocarlos donde los quiera tu propia gramática en vez de extraerlos del inglés.
{
"error": "The Pro plan includes 50 monitors, and you have 50.",
"code": "limit_reached",
"vars": { "plan": "pro", "limit": "50", "current": "50", "resource": "monitors" }
}Es de aquí de donde nuestras propias aplicaciones sacan un rechazo en el idioma de quien lee. Trata un código que no reconozcas igual que ellas — recurre a error — porque se añaden códigos sin cambiar la versión.
Límites de peticiones
Por organización, no por clave — crear otra clave no los sube.
| Bucket | Límite |
|---|---|
Lecturas (GET) | 120 por minuto |
Escrituras (POST, PATCH, DELETE) | 30 por minuto |
| Subidas de source maps | 300 por hora |
Pasarse responde 429 con una cabecera Retry-After que indica los segundos enteros que faltan para que la ventana se reinicie. Respétela en lugar de reintentar de inmediato.
Están puestos donde una integración normal nunca llega: un panel de pared que consulta cada diez segundos gasta seis de las 120 lecturas. Son iguales en todos los planes, porque los endpoints de colección devuelven todo en una sola respuesta — una cuenta con quinientos monitores no necesita más peticiones que una con veinte. Los source maps tienen una ventana por hora porque llegan en bloque al desplegar, donde un front end puede tener cien chunks.
404 en lugar de 403, a propósito
Un id que pertenece a otro cliente responde «Not found.», no «Forbidden.». Un 403 confirmaría que el registro existe, lo que convertiría al endpoint en una forma de averiguar si un id es real. No lea un 404 como prueba de que algo no existe en ninguna parte — solo de que no existe nada que esta clave pueda ver.
Endpoints
GET /search
Todo lo que coincide con ?q= en la cuenta: monitores, incidencias y sus análisis posteriores, servidores, páginas de estado, espacios de trabajo, canales de notificación, ventanas de mantenimiento, proyectos de errores y problemas, sitios de analítica, miembros e invitaciones, claves de API, agentes y sondas privadas. Una sola petición en lugar de una por tipo.
?type= limita a una lista de tipos separada por comas y ?limit= limita los resultados de cada tipo entre 1 y 20 (5 por defecto). Cada tipo exige el mismo permiso que su propio endpoint; un tipo que su clave no puede leer está ausente igual que un tipo sin coincidencias. No se busca ni se devuelve nada sellado, cifrado ni secreto.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
limit | query | integer |
q | query | string |
type | query | string |
| Respuesta | SearchResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /summary
Conteos, para un panel de pared o un resumen diario. Requiere monitor:read.
{
"data": {
"total": 42, "up": 39, "degraded": 1, "down": 1,
"paused": 1, "pending": 0,
"openIncidents": 2, "suppressedIncidents": 1
}
}suppressedIncidents cuenta los incidentes retenidos por ser el alcance de otro. Son reales, y no son caídas separadas.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | GetSummaryResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /setup
Lo que a una cuenta nueva le queda por hacer: las mismas cuatro preguntas que hace la lista de puesta en marcha del panel, derivadas en cada lectura. Requiere monitor:read.
{
"data": {
"hasMonitor": true,
"hasConfirmedChannel": false,
"hasStatusPage": false,
"hasColleague": false,
"dismissedAt": null
}
}hasConfirmedChannel pregunta si una alerta podría llegar de verdad, no si existe un canal. Las dos cosas se separaron feamente una vez, y una lista que diera la alerta por montada con un canal al que no servimos repetiría aquel fallo en forma de tranquilidad.
hasColleague cuenta pertenencias y nunca invitaciones: una invitación enviada y no aceptada no ha añadido a nadie.
No está plegado en /summary porque ese endpoint son recuentos por estado y nada más: un panel de pared que lo consulta cada pocos segundos no quiere cinco consultas de más para pintar un aviso dirigido a quien montó la cuenta hace meses.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | GetSetupResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
DELETE /setup
Omite la lista. Requiere org:update, porque descartarla es una fila de toda la organización y no una preferencia de cada persona: a quien llegue después no se le vuelve a mostrar.
Nada más cambia en la cuenta y no se escribe entrada de auditoría: ocultar un aviso no cambia nada de cómo se comporta el producto, ni de cómo alerta, ni de cómo factura.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | DismissedResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /monitors
Todos los monitores que la clave puede ver. Requiere monitor:read. Cada uno lleva id, name, kind, status, statusSince, enabled, intervalSeconds, tags, workspace, lastCheckedAt, lastResponseTimeMs, lastMessage, uptime24h, uptime30d y openIncidentId.
?tag=prod,eu reduce la lista a los monitores que llevan todas las etiquetas nombradas — Y, no O, de modo que nombrar una segunda etiqueta siempre devuelve menos monitores en lugar de más. El filtro del panel se lee igual. Las etiquetas se guardan en minúsculas, y aquí el valor se convierte del mismo modo antes de compararlo, así que ?tag=Prod las encuentra. Una entrada que no podría ser una etiqueta —vacía, o más larga de lo que una etiqueta admite— se descarta y el resto del filtro sigue aplicándose, en vez de rechazar la llamada: un enlace no debería dejar de funcionar porque se renombró una de sus etiquetas.
config nunca se devuelve. En algunos tipos contiene cabeceras de solicitud y credenciales, y una clave de solo lectura no debería ser una forma de recuperar los secretos que alguien escribió en un formulario.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
tag | query | string |
| Respuesta | ListMonitorsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /monitors
Requiere monitor:create. Necesita name, kind, workspaceId y config. Opcionales: intervalSeconds (por defecto 300), confirmations, dependsOn.
curl -X POST https://vitrinaengine.com/api/v1/monitors \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Marketing site",
"kind": "http",
"workspaceId": "…",
"intervalSeconds": 60,
"config": {
"url": "https://example.com",
"assertions": [{ "type": "status_code", "operator": "lt", "value": "400" }]
}
}'Responde 201 con el id nuevo. El intervalo se ajusta al mínimo de su plan en lugar de rechazarse, así que pedir 10 segundos en un plan cuyo mínimo es 60 le da 60 — si le importa, vuelva a leerlo.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
kind | body | string |
workspaceId | body | string |
config | body | string |
intervalSeconds | body | integer |
confirmations | body | integer |
dependsOn | body | string[] |
probeId | body | string |
tags | body | string[] |
| Respuesta | CreatedResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /monitors/{id}
Un monitor, con todo lo que da la lista más paused. Requiere monitor:read.
Para mail_posture, tls_audit y snmp incluye además lastCheckDetail, el resultado de la última comprobación: los hallazgos detrás del estado, cada uno con un code estable y una severity, más una nota TLS o las lecturas SNMP. Es null hasta la primera comprobación y no aparece en los demás tipos.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetMonitorResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PATCH /monitors/{id}
Envíe solo lo que quiera cambiar: name, intervalSeconds, confirmations, enabled, config o paused.
paused se comprueba contra monitor:pause y todo lo demás contra monitor:update, por separado — una clave que puede pausar pero no editar todavía puede pausar. Enviar un cambio vacío es un 400.
El monitor se vuelve a leer y se devuelve, en lugar de repetirle lo que envió, así que lo que ve es lo que quedó guardado.
# Silence a monitor for the length of a deploy.
curl -X PATCH https://vitrinaengine.com/api/v1/monitors/$ID \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"paused": true}'Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
name | body | string |
intervalSeconds | body | integer |
confirmations | body | integer |
enabled | body | boolean |
paused | body | boolean |
config | body | string |
tags | body | StringList |
| Respuesta | UpdatedMonitorResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /monitors/{id}
Requiere monitor:delete. Responde { "data": { "id": "…", "deleted": true } }.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /hosts · POST /hosts
Los servidores son la segunda forma de agrupar monitores: el espacio de trabajo dice de quién es un monitor, el servidor dice dónde corre. Totalmente opcional: una cuenta que nunca cree uno no pierde nada, y la mayoría de los monitores no nombran ningún servidor.
Cada servidor trae status, pinned y spanning. status se deriva solo de los monitores que corren únicamente en ese servidor. Un monitor que corre en varias máquinas cuenta en spanning y no colorea a ninguna, porque cuando falla un endpoint balanceado eso dice que el servicio está roto, no qué máquina lo rompió. Un servidor sin nada propio responde "status": null en lugar de up.
POST requiere monitor:create y un name. Los campos opcionales provider, address y notes son suyos: nada en el producto los usa. Un nombre que coincide con uno que ya tiene — ignorando mayúsculas y el punto final — responde 409.
Parámetros y respuestas
GET /hosts
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListHostsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /hosts
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
provider | body | string |
address | body | string |
notes | body | string |
| Respuesta | CreatedResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /hosts/{id} · PATCH /hosts/{id} · DELETE /hosts/{id}
El detalle trae el servidor y sus monitores, cada uno marcado con pinned y, cuando no lo está, con alsoOn: las otras máquinas desde las que responde, que es lo que usted lee antes de reiniciar una. DELETE retira el servidor y todos sus monitores siguen funcionando: un servidor no tiene horario ni historial propios.
Parámetros y respuestas
GET /hosts/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetHostResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PATCH /hosts/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
name | body | string |
provider | body | string |
address | body | string |
notes | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /hosts/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /hosts/{id}/monitors · DELETE /hosts/{id}/monitors
Un monitor dentro o fuera de un servidor, con monitorId en el cuerpo o ?monitorId=. Deliberadamente no es una lista completa: en una cuenta de agencia un servidor lleva monitores de varios espacios de trabajo, y quien reemplazara “la lista” estaría reemplazando filas que nunca vio. Ambas direcciones son idempotentes.
Parámetros y respuestas
POST /hosts/{id}/monitors
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
monitorId | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /hosts/{id}/monitors
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
monitorId | query | string |
monitorId | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /monitors/{id}/hosts · PUT /monitors/{id}/hosts
El otro lado de la misma relación, y este sí es una lista completa: estos vínculos pertenecen a un solo monitor, así que no hay nada del otro lado que otro espacio de trabajo pueda ver. Envíe hostIds; un arreglo vacío es una petición real y significa que el monitor no corre en ningún servidor en particular. Los ids que no son suyos se descartan en vez de rechazarse. Toda respuesta de monitor trae además hosts, vacío cuando no hay ninguno.
Parámetros y respuestas
GET /monitors/{id}/hosts
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | ListMonitorHostsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PUT /monitors/{id}/hosts
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
hostIds | body | string[] |
| Respuesta | ListMonitorHostsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /incidents
Requiere incident:read. Acepta ?status= — uno de open, acknowledged, resolved o suppressed — y ?open=true para los tres que no están resueltos. Un estado que no se reconoce se ignora en lugar de rechazarse, igual que ?limit= (por defecto 50) se ajusta a 200 en vez de rechazarse.
Cada uno lleva id, monitorId, monitorName, title, cause, status, severity, startedAt, resolvedAt, durationSeconds, acknowledgedAt y rootIncidentId.
rootIncidentId es el campo que mirar si arma un feed de alertas. Cuando está presente, este incidente es el alcance de otro — se cayó el servidor de base de datos y este es uno de los doce servicios que están detrás. Sáltelos y recibe una alerta en lugar de trece.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
limit | query | integer |
open | query | boolean |
status | query | string |
| Respuesta | ListIncidentsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /incidents/{id}
Un incidente. Requiere incident:read. Los mismos campos que la lista, más workspaceId.
No devuelve la cronología del incidente — los comentarios y los cambios de estado que se ven en el panel no están en este endpoint. Si los necesita, dígalo y se pueden agregar; documentarlos aquí sin que existan sería peor que la ausencia.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetIncidentResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PATCH /incidents/{id}
Envíe status con valor "acknowledged" o "resolved", o un comment, o ambos. Cada uno se comprueba contra su propio permiso: incident:acknowledge, incident:resolve, incident:comment. Agregar "publish": true a un comentario lo publica en la página de estado y requiere además status_page:manage.
# A runbook that fixed the thing itself can close its own incident.
curl -X PATCH https://vitrinaengine.com/api/v1/incidents/$ID \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"status": "resolved", "comment": "Restarted by runbook.", "publish": true}'Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
status | body | string |
comment | body | string |
publish | body | boolean |
| Respuesta | GetIncidentResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
PUT /incidents/{id}/postmortem
Escribe o reemplaza el análisis posincidente del incidente. Requiere incident:resolve, y el incidente debe estar ya resuelto; si no, 409 con el código incident_not_resolved. Envíe body en Markdown, de 1 a 50.000 caracteres tras recortar espacios (postmortem_required, postmortem_too_long). Hay uno por incidente, así que cada llamada reemplaza el anterior. La respuesta es el incidente, tal como lo devuelve GET /incidents/{id}.
GET /incidents/{id} lo incluye como postmortem: { body, authorName, updatedAt }, o null, y la lista incluye hasPostmortem. Muestre body como Markdown y nunca como HTML: es texto que escribió una persona. Un análisis posincidente es interno y nunca aparece en una página de estado.
curl -X PUT https://vitrinaengine.com/api/v1/incidents/$ID/postmortem \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"body": "## What happened\n\nThe connection pool ran dry after a deploy."}'Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
body | body | string |
| Respuesta | GetIncidentResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /probes
Las sondas privadas de su organización: id, name, lastSeenAt, version, hostname, monitorCount, revoked y createdAt. Requiere agent:read. Es lo que ofrece el selector de sonda de un monitor.
No hay campo de región, ni lo habrá. Usted elige una sonda por su nombre; dónde se ejecuta una comprobación detrás de ella lo decidimos y cambiamos nosotros. Las sondas revocadas aparecen con revoked: true y ya no reciben trabajo, así que no las ofrezca.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListProbesResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /monitors/{id}/push-url
La URL de ping de un monitor heartbeat, mostrada de nuevo. Requiere monitor:read. url es null para un tipo que no recibe pings y para un token que ya no se puede descifrar; el monitor sigue funcionando, y renovar el token en el panel genera una URL que sí se puede mostrar.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetPushUrlResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /organizations · PUT /organizations/active
Las organizaciones a las que pertenece la persona que ha iniciado sesión, cada una con su role allí y active en la que está en uso, y el cambio entre ellas. Envíe organizationId; la respuesta es la membresía que queda en uso.
Solo con sesión iniciada. Una clave pertenece a una única membresía y recibe 403 con session_required. Cambiar mueve todas las sesiones de esa persona, incluido el panel, y una organización a la que no pertenece responde 404.
Parámetros y respuestas
GET /organizations
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListOrganizationsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PUT /organizations/active
| Nombre | Ubicación | Tipo |
|---|---|---|
organizationId | body | string |
| Respuesta | ActiveOrganizationResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /sms/enrolment · POST /sms/enrolment/confirm
Registre su propio número de móvil para alertas por SMS: envíe phone (y opcionalmente name) y le enviaremos un código de seis dígitos; envíe ese code a la segunda ruta para confirmar. Requiere notification_channel:manage y una sesión iniciada: un número lo añade la persona que tiene el teléfono, nunca una clave.
El número se guarda sin confirmar y no recibe nada hasta que vuelve el código. Registrarse de nuevo reemplaza su número anterior. Rechazos: sms_not_included (402, el plan no incluye SMS), not_a_phone_number, sms_country_unsupported, sms_route_not_open, verification_code_not_sent (502; vuelva a llamar para recibir un código nuevo), verification_code_malformed y verification_code_incorrect. Un inicio correcto incluye country y caveat (sender-replaced, registration-pending, unverified o null), que conviene mostrar antes de que alguien dependa del número.
Parámetros y respuestas
POST /sms/enrolment
| Nombre | Ubicación | Tipo |
|---|---|---|
phone | body | string |
name | body | string |
| Respuesta | SmsEnrolmentResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /sms/enrolment/confirm
| Nombre | Ubicación | Tipo |
|---|---|---|
code | body | string |
| Respuesta | SmsConfirmedResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /channels/{id}/confirmation
Reenvía el mensaje de confirmación de un canal de correo. Requiere notification_channel:manage. Cada llamada emite un enlace nuevo y el anterior deja de funcionar. sent: false significa que no había nada que enviar (la dirección ya confirmó), y por esta vía nunca se vuelve a escribir a una dirección confirmada. Un envío rechazado por el proveedor de correo responde 502 con confirmation_not_sent.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | ChannelConfirmationResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
PATCH /workspaces/{id}
Cambia el nombre de un espacio de trabajo. Requiere workspace:update. name es obligatorio (de 1 a 80 caracteres) y clientReference, opcional: null lo borra. El slug nunca cambia, porque figura en las URL de las páginas de estado. La respuesta es el espacio de trabajo tal como queda.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
name | body | string |
clientReference | body | requests.NullableString |
| Respuesta | UpdatedWorkspaceResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /sourcemaps
Suba un source map para que las trazas minificadas se resuelvan. Requiere monitor:create. Necesita projectRef (un número) y filename, más el mapa en sí como map (JSON) o mapGzipBase64. Opcionales: debugId y release.
Envíe un debug id o un release. Un mapa sin ninguno de los dos no se puede asociar a una traza y quedará ahí sin hacer nada. La correspondencia se busca primero por debugId y después por release más nombre de archivo.
Los mapas se resuelven cuando se lee un problema, no al subirlos, así que uno subido después de que llegaran los errores igual sirve — que es el orden habitual.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
projectRef | body | integer |
filename | body | string |
debugId | body | string |
release | body | string |
map | body | string |
mapGzipBase64 | body | string |
| Respuesta | UploadedSourceMapResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 300 por hora |
POST /symbols
La misma idea para una aplicación nativa: suba un .dSYM de iOS o un mapping.txt de R8 en Android para que las trazas de los fallos se resuelvan. Requiere monitor:create. Veinte subidas por hora, y se conservan veinte compilaciones por proyecto.
A diferencia de /sourcemaps, el cuerpo es el propio archivo comprimido con gzip y los metadatos van en cabeceras: X-Vitrina-Project-Ref, X-Vitrina-Platform (ios o android), X-Vitrina-Symbol-Name y X-Vitrina-Release. Un dSYM pesa decenas de megabytes, y ponerlo en base64 dentro de un campo JSON cuesta un tercio más de transferencia.
Las dos plataformas se asocian de forma distinta. Un frame de iOS nombra el UUID Mach-O de la imagen a la que pertenece, así que una subida de iOS debe llevar X-Vitrina-Debug-Ids y se asocia exactamente por él. R8 no emite ningún id de ese tipo, así que un mapping de Android se asocia solo por el release — que debe ser exactamente el que reporta la aplicación, <applicationId>@<versionName>+<versionCode>. Un dígito de diferencia y los frames se resuelven a líneas que parecen plausibles y son falsas.
Volver a subir la misma compilación reemplaza sus símbolos en lugar de fallar, así que un trabajo de publicación reintentado no es un error. Igual que con los source maps, la resolución ocurre cuando se lee un problema.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | UploadedSymbolsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 20 por hora |
GET /errors/projects
Los proyectos de seguimiento de errores de esta cuenta. Requiere monitor:read. Cada uno lleva ref — el número que va en el DSN — más publicKey, unresolved y eventsLast24h. Es de solo lectura: un proyecto se crea con una clave que todavía hay que pegar en la configuración de una aplicación, así que no hay nada aquí que un endpoint pudiera terminar.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListErrorProjectsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /errors/issues
Errores agrupados, primero los de actividad más reciente. Requiere monitor:read. Un problema es una huella y no un evento, así que mil apariciones de una misma excepción son una sola fila con timesSeen en mil. ?status= vale unresolved por defecto y acepta también resolved, ignored o all; ?project= filtra por id de proyecto, ?q= busca en el tipo, el valor y el culpable, y ?limit= tiene un tope de 200. spark son veinticuatro conteos por hora, del más antiguo al más reciente.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
limit | query | integer |
project | query | string |
q | query | string |
status | query | string |
| Respuesta | ListIssuesResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /errors/issues/{id}
Un problema con su traza. Requiere monitor:read. exceptions es la cadena propia del SDK, con el error lanzado al final y sus causas antes, y sus frames se resuelven contra cualquier source map que haya subido — la misma resolución que hace el panel, para que un script y la persona con quien habla nunca estén mirando trazas distintas. Un mapa que no se puede aplicar vuelve a los frames originales en lugar de hacer fallar la petición.
lastEvent lleva dos marcas de tiempo a propósito. occurredAt es lo que reportó el SDK y receivedAt es cuándo lo escribió la ingesta; un dispositivo que estaba sin conexión, o una cola que se atascó, son exactamente la diferencia entre las dos.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetIssueResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PATCH /errors/issues/{id}
Resolver, ignorar o reabrir: { "status": "resolved" }. Requiere monitor:update. ignoreHours puede acompañar a ignored para dejar de ignorarlo más adelante, y tiene un tope de 90 días.
Al resolver se registra el release en el que se resolvió, así que un rezagado de un despliegue anterior no reabre el problema. Cuando el SDK no envió ningún release no hay nada con qué comparar y cualquier evento posterior sí lo reabre — sin forma de distinguir un rezagado de una regresión, lo seguro es suponer que el fallo volvió.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
status | body | string |
ignoreHours | body | integer |
| Respuesta | IssueStatusResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /analytics
Los sitios web que mide esta cuenta. Requiere monitor:read. Lleva publicId — el valor que va en la etiqueta del script, que es público por diseño — más viewsLast24h y trafficAlerting, que es verdadero mientras el tráfico de un sitio está por debajo de lo que esa hora ve normalmente.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListAnalyticsSitesResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /analytics/{id}
Los números de un sitio, para una hoja de cálculo o un reporte. Requiere monitor:read. ?days= vale 7 por defecto y tiene un tope de 365. ?dimensions= acepta una lista separada por comas de path, referrer, country, browser, os, device, utm_source, utm_medium, utm_campaign y event; una desconocida es un 400 y no una respuesta vacía, porque un error de escritura que no devuelve nada se lee como «no hubo tráfico».
La cifra de visitantes se llama dailyUniqueVisitors, y eso es exactamente lo que es. Es la suma de los únicos diarios y no puede ser otra cosa: el secreto detrás del hash de un visitante se destruye al terminar su día UTC, así que alguien que visitó en dos días cuenta dos veces y no hay ninguna clave que los una. Eso es el diseño de privacidad funcionando y no una aproximación — pero un campo llamado visitors junto a un rango de 30 días le invitaría a reportar un número que significa otra cosa.
curl "https://vitrinaengine.com/api/v1/analytics/$ID?days=30&dimensions=path,referrer" \
-H "Authorization: Bearer vte_…"Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
days | query | integer |
| Respuesta | GetAnalyticsSiteResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /billing
El plan, y dónde se factura. Requiere billing:read. Lleva plan, status, cadence, currentPeriodEnd, cancelAt, addOnPacks y los últimos doce comprobantes.
source es paddle, apple, manual o none. Importa: una suscripción comprada en la aplicación de iOS le corresponde a Apple, y el plan, la tarjeta y la cancelación viven en los ajustes de la App Store del cliente y no aquí. canCheckoutOnWeb y canPurchaseInApp dicen qué ofertas es seguro mostrar, para que un cliente no tenga que volver a deducir esa regla y equivocarse en la dirección que le cobra dos veces a alguien.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | GetBillingResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /monitors/{id}/history
Disponibilidad diaria de un monitor. Requiere monitor:read. Acepta days, hasta la retención de historial de su plan.
Se calcula a partir de los resúmenes diarios y no de los resultados individuales de cada verificación, que es por lo que sigue respondiendo para periodos cuyos resultados en bruto ya borró la retención.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
days | query | integer |
| Respuesta | GetMonitorHistoryResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /monitors/{id}/graph · GET /monitors/graphs
Las últimas horas de un monitor, hora a hora, o de todos los monitores que ve esta clave en una sola respuesta — lo que el panel dibuja en la fila y la página de un monitor. Requiere monitor:read. Acepta hours, 24 por defecto y 168 como máximo.
Un gráfico uptime lleva la proporción de verificaciones superadas en cada hora, con null para una hora sin ninguna; un gráfico value, para los tipos cuantitativos, lleva sus lecturas como series con su unidad. Cada hora de la ventana está presente se registrara algo o no, de modo que un hueco se ve como hueco. Las lecturas se envían tal como se midieron: una serie raw no tiene escala conocida, así que dibújela frente a su propia lectura más alta y nunca muestre esa proporción como si fuera la lectura.
Parámetros y respuestas
GET /monitors/{id}/graph
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
hours | query | integer |
| Respuesta | GetMonitorGraphResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /monitors/graphs
| Nombre | Ubicación | Tipo |
|---|---|---|
hours | query | integer |
| Respuesta | ListMonitorGraphsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /monitors/{id}/channels · PUT /monitors/{id}/channels
A qué canales alerta este monitor, y cómo fijarlos. Leer requiere notification_channel:read; escribir requiere monitor:update.
PUT reemplaza el conjunto entero — envíe todos los ids de canal que quiera, no solo los que está agregando. Un arreglo vacío significa que el monitor no alerta a nadie, lo que es algo válido de querer y algo malo de hacer por descuido.
Parámetros y respuestas
GET /monitors/{id}/channels
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetMonitorChannelsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PUT /monitors/{id}/channels
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
channelIds | body | StringList |
| Respuesta | GetMonitorChannelsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /incidents/{id}/events
La cronología de un incidente: cambios de estado, acuses de recibo, comentarios y pasos de escalamiento. Requiere incident:read. Esta es la cronología que GET /incidents/{id} no incluye.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | ListIncidentEventsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /channels · POST /channels
Leer requiere notification_channel:read; crear requiere notification_channel:manage. Cada uno lleva id, kind, name, target y workspaceId.
secret se devuelve solo al crear un canal, y nunca más. Es la clave de firma de un webhook; guardarla donde pudiera volver a leerse convertiría una clave de solo lectura en una forma de falsificar peticiones firmadas.
Puede crear los tipos que una persona puede crear en el panel: email, webhook, telegram, slack, teams, discord, pagerduty y jsm. SMS, WhatsApp, satélite y push los registra la persona que los recibe y no pueden crearse por la API — eso es lo que los hace consentimiento y no un campo que alguien escribió.
Un canal de correo se crea sin confirmar y recibe un solo mensaje preguntándole si quiere alertas. No se envía nada más hasta que acepte, así que crear uno por la API no pone por sí solo una dirección en su rotación de avisos.
Parámetros y respuestas
GET /channels
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListChannelsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /channels
| Nombre | Ubicación | Tipo |
|---|---|---|
kind | body | string |
name | body | string |
target | body | string |
workspaceId | body | requests.NullableString |
| Respuesta | CreatedChannelResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
PATCH /channels/{id} · DELETE /channels/{id} · POST /channels/{id}/test
Todos requieren notification_channel:manage. El envío de prueba se rechaza para una dirección que no ha confirmado — de lo contrario sería una forma ilimitada de escribirle a una dirección sin consentimiento, con una etiqueta servicial encima.
Parámetros y respuestas
PATCH /channels/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
enabled | body | boolean |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /channels/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /channels/{id}/test
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | TestDeliveryResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /status-pages · POST /status-pages
Leer requiere status_page:read; escribir requiere status_page:manage. Cada una lleva id, name, slug, visibility, customDomain, domainVerifiedAt, subscribersEnabled, componentCount, workspace y createdAt.
Parámetros y respuestas
GET /status-pages
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListStatusPagesResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /status-pages
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
workspaceId | body | string |
| Respuesta | CreatedResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /status-pages/{id} · PATCH /status-pages/{id} · DELETE /status-pages/{id}
Leer requiere status_page:read; cambiar o eliminar requiere status_page:manage.
Parámetros y respuestas
GET /status-pages/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | GetStatusPageResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
PATCH /status-pages/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
name | body | string |
headline | body | requests.NullableString |
description | body | requests.NullableString |
logoUrl | body | requests.NullableString |
themeAccent | body | string |
language | body | string |
historyDays | body | integer |
showResponseTimes | body | boolean |
showIncidentHistory | body | boolean |
subscribersEnabled | body | boolean |
visibility | body | string |
password | body | requests.NullableString |
customCss | body | requests.NullableString |
hideVitrinaBranding | body | boolean |
groupByHost | body | boolean |
| Respuesta | UpdatedStatusPageResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /status-pages/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /status-pages/{id}/components · DELETE /status-pages/{id}/components
Agregar o quitar un monitor de una página. Requiere status_page:manage.
El monitor tiene que estar en el mismo espacio de trabajo que la página, no solo en la misma organización. En una cuenta de agencia eso es lo que impide que el monitor de un cliente se publique en la página de otro.
Parámetros y respuestas
POST /status-pages/{id}/components
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
monitorId | body | string |
displayName | body | string |
| Respuesta | ComponentAckResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /status-pages/{id}/components
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
component | query | string |
componentId | body | string |
| Respuesta | ComponentAckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /workspaces · POST /workspaces · DELETE /workspaces/{id}
Leer requiere workspace:read, y el resto sus propios permisos. Cada uno lleva id, name, slug, clientReference e isDefault.
La clave de un miembro confinado ve solo los espacios de trabajo a los que ese miembro está confinado. El espacio de trabajo predeterminado no se puede eliminar.
Parámetros y respuestas
GET /workspaces
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListWorkspacesResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /workspaces
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
clientReference | body | string |
| Respuesta | CreatedResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /workspaces/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /members · POST /members
Leer requiere member:read; invitar requiere member:invite. La respuesta trae members e invitations por separado — una invitación que nadie ha aceptado no ha agregado a nadie, y juntarlas daría un recuento de puestos que no coincide con lo que se le factura.
POST envía una invitación en lugar de crear una cuenta. Acepta un correo, un rol y, si quiere, workspaceIds para confinar a esa persona.
Parámetros y respuestas
GET /members
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListMembersResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /members
| Nombre | Ubicación | Tipo |
|---|---|---|
email | body | string |
role | body | string |
workspaceIds | body | string[] |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
PATCH /members/{id} · DELETE /members/{id} · DELETE /invitations/{id}
Cambiar un rol requiere member:update_role; quitar a alguien requiere member:remove; revocar una invitación requiere member:invite.
Quitar a un miembro elimina sus canales de alerta personales — su teléfono, su chat privado, su número móvil — junto con sus claves de API. Los canales compartidos no se tocan. Al último propietario no se le puede quitar ni bajar de rol.
Parámetros y respuestas
PATCH /members/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
role | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /members/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /invitations/{id}
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /maintenance · POST /maintenance · DELETE /maintenance
Ventanas durante las cuales nada avisa a nadie. Por omisión las verificaciones siguen corriendo y registrando, así que esos minutos cuentan para la disponibilidad como cualquier otro; con keepChecking en false no se comprueba nada mientras la ventana está abierta, lo que deja un hueco en el historial en lugar de un bajón. Leer requiere incident:read; escribir requiere maintenance:manage.
Lleva title, startsAt, endsAt, timezone, monitorIds, recurrenceRule, keepChecking, showOnStatusPage y notifySubscribers. Una ventana periódica es una sola fila, no muchas.
Una regla repite la ventana a la misma hora local en su propia timezone, así que una ventana que cruza un cambio de hora se mantiene en la hora prevista. FREQ=DAILY, FREQ=WEEKLY y FREQ=MONTHLY se expanden, opcionalmente con INTERVAL, COUNT, UNTIL y un BYDAY o BYMONTHDAY que nombre el día en que empieza la propia ventana. Cualquier otra regla se guarda y se devuelve sin cambios y solo retiene las alertas en su primera ocurrencia: nunca se adivina.
Parámetros y respuestas
GET /maintenance
| Nombre | Ubicación | Tipo |
|---|---|---|
past | query | boolean |
| Respuesta | ListMaintenanceResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /maintenance
| Nombre | Ubicación | Tipo |
|---|---|---|
title | body | string |
description | body | string |
workspaceId | body | string |
monitorIds | body | string[] |
startsAt | body | string |
endsAt | body | string |
recurrenceRule | body | string |
timezone | body | string |
keepChecking | body | boolean |
showOnStatusPage | body | boolean |
notifySubscribers | body | boolean |
| Respuesta | CreatedResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /maintenance
| Nombre | Ubicación | Tipo |
|---|---|---|
id | query | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /on-call
Horarios, políticas de escalamiento, reemplazos y quién está de guardia ahora mismo. Requiere oncall:read.
onCallNow se resuelve en el momento en que pregunta, con viaOverride indicando si salió de la rotación o de alguien que está cubriendo. unreachable nombra a los participantes que no tienen ningún canal por el que se les pueda alcanzar de verdad, que es la falla que conviene detectar antes de un incidente y no durante.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | GetOnCallResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /agents · POST /agents · DELETE /agents · GET /agents/{id}/metrics
Los agentes de servidor reportan CPU, memoria y disco desde sus propias máquinas. Registrarlos requiere agent:enroll, leerlos requiere agent:read, quitarlos requiere agent:delete.
Registrar uno devuelve un token, una sola vez. Es con lo que el agente se autentica, así que después ya no se puede leer.
Parámetros y respuestas
GET /agents
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListAgentsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /agents
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
workspaceId | body | requests.NullableString |
| Respuesta | EnrolledAgentResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /agents
| Nombre | Ubicación | Tipo |
|---|---|---|
id | query | string |
id | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /agents/{id}/metrics
| Nombre | Ubicación | Tipo |
|---|---|---|
id obligatorio | path | string |
hours | query | integer |
limit | query | integer |
| Respuesta | GetAgentMetricsResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /api-keys · POST /api-keys · DELETE /api-keys
Leer requiere api_key:read; crear y revocar requieren api_key:manage. Cada una lleva id, name, prefix, scopes, workspaceIds, owner, createdAt, lastUsedAt, expiresAt y revokedAt.
token se devuelve solo al crearla. prefix es la parte que se puede mostrar, que es lo que le permite distinguir dos claves en una lista sin que ninguna sea legible.
Una clave hereda el rol y el confinamiento a espacios de trabajo de la membresía que la creó, así que una clave no puede ser una forma de rodear un límite que tiene quien la creó.
Parámetros y respuestas
GET /api-keys
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | ListApiKeysResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
POST /api-keys
| Nombre | Ubicación | Tipo |
|---|---|---|
name | body | string |
scopes | body | string[] |
workspaceIds | body | string[] |
expiresInDays | body | requests.NullableInt64 |
| Respuesta | CreatedApiKeyResponse |
|---|---|
| Códigos de estado | 201 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
DELETE /api-keys
| Nombre | Ubicación | Tipo |
|---|---|---|
id | query | string |
id | body | string |
| Respuesta | AckResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /audit
Cambios de configuración, con quién los hizo y qué cambió. Requiere audit_log:read, que es del plan Business en adelante.
Se pagina con nextBefore y no por número de página, así que el corte entre páginas no se mueve mientras las está leyendo. Las entradas se registran en todos los planes — el plan controla la lectura, así que subir de nivel abre todo el historial en lugar de empezar uno.
Nunca se escriben credenciales, hashes ni secretos en changes.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
limit | query | integer |
| Respuesta | ListAuditResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
GET /me
Quién es esta clave, a qué alcanza y qué permite el plan. No requiere permiso alguno — toda clave puede describirse a sí misma.
Lleva user, organization, membership(rol y confinamiento a espacios de trabajo), entitlements (los límites del plan ya resueltos, con los paquetes adicionales ya incorporados) y usage. Úselo para comprobar un límite antes de intentar crear algo, en lugar de después de que se lo rechacen.
Una sesión recibe además organizations, con todas las organizaciones a las que pertenece la persona. Una clave de API no: una clave se emite contra una sola membresía y queda confinada a ella, así que listar las demás anunciaría organizaciones a las que esa credencial no llega.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | GetMeResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 120 por minuto |
DELETE /account
Elimina la organización y todo lo que hay dentro. Ninguna constante de permiso protege esta ruta porque la comprobación es la propiedad: se rechaza para quien no sea propietario.
Esto no se puede deshacer y no es una pausa. Úselo de forma deliberada.
Parámetros y respuestas
Sin parámetros ni campos de cuerpo declarados.
| Respuesta | AccountDeletedResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
POST /billing/apple/verify
Confirma una compra dentro de nuestra propia aplicación móvil. Requiere billing:manage.
Está documentado por completitud y no para usarlo: solo se puede llamar con un comprobante que Apple emitió para nuestra aplicación, así que no hay nada que una integración de terceros pueda hacer con él. Aparece aquí porque una ruta que existe y no se describe en ninguna parte es indistinguible de una que a alguien se le olvidó.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
transactionId | body | string |
| Respuesta | AppleVerifyResponse |
|---|---|
| Códigos de estado | 200 400 401 403 404 429 |
| Límite de peticiones | 30 por minuto |
GET /
El índice. Lista las rutas que sirve este despliegue, que es la versión legible por máquinas de esta página y siempre está al día — se genera a partir de lo que de verdad está montado.
Canal de incidentes (RSS y Atom)
Todos los incidentes de su cuenta como canal, para un lector y no para una biblioteca cliente. Cree la URL en el panel, en Ajustes → Notificaciones:
https://vitrinaengine.com/feeds/incidents/vtf_…/feed.xml
https://vitrinaengine.com/feeds/incidents/vtf_…/atom.xmlLa URL es la credencial. No hay ninguna cabecera que enviar: quien tenga el enlace puede leer todos los incidentes de la cuenta, de todos los espacios de trabajo. Se muestra en el panel siempre que la necesite otra vez, porque vive en un lector de canales que alguien acabará reinstalando — y puede sustituirse o revocarse, con efecto en la siguiente petición y no cuando caduque una caché.
Lleva solo hechos del incidente: el nombre del monitor, la causa, la gravedad, el estado, cuándo se abrió y se cerró, y las novedades marcadas como públicas. Nunca un análisis posterior, nunca la configuración del monitor y nunca desde dónde se ejecutó una comprobación. La mayoría de los lectores sincronizan a través de servidores ajenos, así que el documento está escrito como si saliera de su edificio, porque sale.
Consultarlo una vez por minuto es lo previsto. A partir de sesenta peticiones por minuto para una URL responde 429, y una URL que nunca fue válida, que se ha sustituido o que se ha revocado responde 404 — la misma respuesta para los tres casos, de modo que no sirva para averiguar qué tokens fueron reales.
Lo que esta API deliberadamente no devuelve
- El
configde un monitor. Puede contener credenciales. - Desde qué región se ejecutó una verificación. Dónde verificamos es decisión nuestra y podemos cambiarlo a medida que colocamos y movemos sondas. Sería una promesa sobre nuestra infraestructura sobre la que usted no podría actuar, y tampoco se muestra en ninguna otra parte del producto.
Exporting your data
Two routes hand back a file rather than a message, so that taking your data out does not mean paging through a collection endpoint a thousand times. Both are on every plan, the free one included — what a plan changes is how much history there is to export, not whether you may.
GET /export/{entity}
Un tipo de filas, en CSV o JSON. entity es uno de monitors, hosts, status-pages, notification-channels, members, incidents, incident-events, postmortems, audit-log, error-issues, uptime-daily, uptime-hourly o analytics-hourly. Cualquier otro responde 404.
format es csv (por defecto) o json. from y to son marcas de tiempo RFC 3339. bom añade una marca de orden de bytes UTF-8 al CSV: Excel la necesita para los nombres con caracteres no ASCII, y la mayoría de los lenguajes de scripting la leen como parte del primer encabezado de columna, así que está desactivada salvo que la pidas.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
entity obligatorio | path | string |
bom | query | boolean |
format | query | string |
from | query | string |
to | query | string |
| Códigos de estado | 200 400 401 403 404 429 |
|---|---|
| Límite de peticiones | 6 por hora |
GET /export
Todo lo que la clave puede leer, en un zip: un archivo por entidad más manifest.json, que indica qué contiene, cuántas filas tiene cada archivo y qué entidades faltan. Lo que el rol de la clave no puede leer se omite en vez de rechazar la petición entera, y el manifiesto evita que eso ocurra en silencio.
Parámetros y respuestas
| Nombre | Ubicación | Tipo |
|---|---|---|
bom | query | boolean |
format | query | string |
from | query | string |
to | query | string |
| Códigos de estado | 200 400 401 403 404 429 |
|---|---|
| Límite de peticiones | 6 por hora |
What an export does not contain
Una exportación no contiene nada que autentique: ni configuración de canales, ni tokens de heartbeat, ni hashes de contraseñas. La configuración de un monitor sí va incluida, sin nada con forma de credencial — cuerpo de la petición, cabeceras, cadena de comunidad SNMP, credenciales de buzón. Los resultados de comprobación en bruto tampoco están: la retención los elimina, así que la disponibilidad procede de los agregados.
Size, and the one refusal you may meet
Las series horarias están limitadas a 92 días por petición; una ventana mayor se rechaza con export_window_too_wide en lugar de recortarse en silencio. Límite propio: 6 exportaciones por hora y organización.
Versionado
La versión va en la ruta. Se agregarán campos a las respuestas — trate los desconocidos como algo a ignorar y no como un error — pero nada se quitará de v1 ni cambiará de significado dentro de ella.
¿Falta algo?
La superficie es deliberadamente pequeña: cubre un panel de pared, un resumen en un chat y un script de despliegue que silencia un monitor mientras dura una publicación. Si está construyendo algo que no alcanza, escriba a support@vitrinaengine.com — saber qué quiere la gente de verdad es como se elige el siguiente endpoint.