Endpoints
URL base: https://api.zelta.dev/grid/v1
Todos los endpoints requieren autenticacion mediante token Bearer. Consulta la para obtener tu token.
Pantallas (Screens)
Listar pantallas
GET /screensParametros de consulta:
| Parametro | Tipo | Descripcion |
|---|---|---|
page | integer | Numero de pagina (default: 1) |
per_page | integer | Resultados por pagina (default: 25, max: 100) |
status | string | Filtrar por estado: online, offline, standby |
group_id | string | Filtrar por grupo de pantallas |
search | string | Buscar por nombre de pantalla |
Ejemplo:
curl -X GET "https://api.zelta.dev/grid/v1/screens?status=online" \
-H "Authorization: Bearer {token}"Respuesta:
{
"data": [
{
"id": "scr_abc123",
"name": "Recepcion - Planta Baja",
"status": "online",
"orientation": "landscape",
"resolution": "1920x1080",
"current_playlist_id": "pl_xyz789",
"group_id": "grp_001",
"last_sync": "2026-03-11T14:30:00Z",
"uptime_hours": 720,
"created_at": "2026-01-10T09:00:00Z"
}
],
"meta": {
"current_page": 1,
"total_pages": 2,
"total_count": 15
}
}Scope requerido: grid:screens:read
Obtener pantalla
GET /screens/{screen_id}Vincular pantalla
POST /screensCuerpo de la peticion:
{
"pairing_code": "482715",
"name": "Vitrina Principal",
"group_id": "grp_001",
"orientation": "landscape",
"location": {
"name": "Sucursal Centro",
"address": "Av. Reforma 123, CDMX"
}
}Scope requerido: grid:screens:write
Actualizar pantalla
PATCH /screens/{screen_id}Cuerpo de la peticion:
{
"name": "Vitrina Principal - Actualizado",
"orientation": "portrait",
"volume": 75,
"brightness": 80
}Ejecutar accion remota
POST /screens/{screen_id}/actionsCuerpo de la peticion:
{
"action": "restart_app",
"reason": "Actualizacion de contenido"
}Acciones disponibles: restart_app, restart_device, screenshot, force_sync, clear_cache
Desvincular pantalla
DELETE /screens/{screen_id}Scope requerido: grid:screens:write
Atencion
Desvincular una pantalla elimina toda su configuracion, programaciones y analiticas asociadas. El dispositivo mostrara la pantalla de vinculacion nuevamente.
Medios (Media)
Listar medios
GET /mediaParametros de consulta:
| Parametro | Tipo | Descripcion |
|---|---|---|
page | integer | Numero de pagina (default: 1) |
per_page | integer | Resultados por pagina (default: 25, max: 100) |
type | string | Filtrar por tipo: image, video |
folder_id | string | Filtrar por carpeta |
search | string | Buscar por nombre de archivo |
tag | string | Filtrar por etiqueta |
Scope requerido: grid:media:read
Subir medio
POST /mediaCuerpo (multipart/form-data):
| Campo | Tipo | Requerido | Descripcion |
|---|---|---|---|
file | file | Si | Archivo de imagen o video |
name | string | No | Nombre personalizado del archivo |
folder_id | string | No | ID de la carpeta de destino |
tags | string[] | No | Etiquetas para organizar el archivo |
Ejemplo con curl:
curl -X POST https://api.zelta.dev/grid/v1/media \
-H "Authorization: Bearer {token}" \
-F "file=@promo-verano.mp4" \
-F "name=Promocion Verano 2026" \
-F "folder_id=fld_promos" \
-F "tags[]=promocion" \
-F "tags[]=verano"Scope requerido: grid:media:write
Obtener medio
GET /media/{media_id}Actualizar medio
PATCH /media/{media_id}Eliminar medio
DELETE /media/{media_id}Eliminacion segura
Si el medio esta siendo utilizado en una playlist o layout activo, la API devolvera un error 409 Conflict. Debes remover el medio de todas las playlists antes de eliminarlo, o usar el parametro force=true.
Playlists
Listar playlists
GET /playlistsParametros de consulta:
| Parametro | Tipo | Descripcion |
|---|---|---|
page | integer | Numero de pagina (default: 1) |
per_page | integer | Resultados por pagina (default: 25, max: 100) |
search | string | Buscar por nombre de playlist |
screen_id | string | Filtrar playlists asignadas a una pantalla |
Crear playlist
POST /playlistsCuerpo de la peticion:
{
"name": "Promociones Marzo",
"items": [
{
"media_id": "med_img001",
"duration": 10,
"transition": "fade",
"transition_duration": 1
},
{
"media_id": "med_vid002",
"transition": "slide",
"transition_duration": 0.5
},
{
"media_id": "med_img003",
"duration": 8,
"transition": "cut"
}
],
"playback_mode": "loop",
"shuffle": false
}Scope requerido: grid:playlists:write
Obtener playlist
GET /playlists/{playlist_id}Respuesta:
{
"id": "pl_xyz789",
"name": "Promociones Marzo",
"items": [
{
"id": "item_001",
"media_id": "med_img001",
"media_name": "Banner principal",
"media_type": "image",
"duration": 10,
"transition": "fade",
"position": 1
}
],
"playback_mode": "loop",
"total_duration": 85,
"screens_count": 3,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-10T15:30:00Z"
}Actualizar playlist
PATCH /playlists/{playlist_id}Eliminar playlist
DELETE /playlists/{playlist_id}Layouts
Listar layouts
GET /layoutsCrear layout
POST /layoutsCuerpo de la peticion:
{
"name": "Ofertas + Redes Sociales",
"resolution": "1920x1080",
"zones": [
{
"id": "zone_main",
"x": 0,
"y": 0,
"width": "70%",
"height": "100%",
"content_type": "playlist",
"content_id": "pl_xyz789"
},
{
"id": "zone_sidebar",
"x": "70%",
"y": 0,
"width": "30%",
"height": "100%",
"content_type": "playlist",
"content_id": "pl_social456"
}
]
}Scope requerido: grid:playlists:write
Obtener layout
GET /layouts/{layout_id}Actualizar layout
PATCH /layouts/{layout_id}Eliminar layout
DELETE /layouts/{layout_id}Programaciones (Schedules)
Listar programaciones
GET /schedulesParametros de consulta:
| Parametro | Tipo | Descripcion |
|---|---|---|
screen_id | string | Filtrar por pantalla |
group_id | string | Filtrar por grupo |
active | boolean | Solo programaciones activas |
from | date | Fecha de inicio (ISO 8601) |
to | date | Fecha de fin (ISO 8601) |
Crear programacion
POST /schedulesCuerpo de la peticion:
{
"name": "Horario laboral",
"screen_ids": ["scr_abc123", "scr_def456"],
"priority": 3,
"rules": [
{
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"time_start": "09:00",
"time_end": "18:00",
"playlist_id": "pl_xyz789"
},
{
"days": ["saturday", "sunday"],
"time_start": "10:00",
"time_end": "14:00",
"playlist_id": "pl_weekend123"
}
],
"date_range": {
"start": "2026-03-01",
"end": "2026-12-31"
},
"active": true
}Scope requerido: grid:schedules:write
Obtener programacion
GET /schedules/{schedule_id}Actualizar programacion
PATCH /schedules/{schedule_id}Eliminar programacion
DELETE /schedules/{schedule_id}Analiticas (Analytics)
Resumen de reproducciones
GET /analytics/playbackParametros de consulta:
| Parametro | Tipo | Descripcion |
|---|---|---|
screen_id | string | Filtrar por pantalla |
media_id | string | Filtrar por archivo multimedia |
playlist_id | string | Filtrar por playlist |
from | date | Fecha de inicio (ISO 8601) |
to | date | Fecha de fin (ISO 8601) |
group_by | string | Agrupar por: screen, media, playlist, day, hour |
Ejemplo:
curl -X GET "https://api.zelta.dev/grid/v1/analytics/playback?from=2026-03-01&to=2026-03-11&group_by=media" \
-H "Authorization: Bearer {token}"Respuesta:
{
"data": [
{
"media_id": "med_img001",
"media_name": "Banner principal",
"total_plays": 1520,
"total_duration_seconds": 15200,
"unique_screens": 5,
"completion_rate": 100
},
{
"media_id": "med_vid002",
"media_name": "Video promocional",
"total_plays": 890,
"total_duration_seconds": 26700,
"unique_screens": 3,
"completion_rate": 94.5
}
],
"meta": {
"period": {
"from": "2026-03-01",
"to": "2026-03-11"
},
"total_plays": 2410
}
}Scope requerido: grid:analytics:read
Estado de pantallas
GET /analytics/screens/statusRespuesta:
{
"total_screens": 15,
"online": 13,
"offline": 1,
"standby": 1,
"average_uptime_percent": 99.2
}Grupos (Groups)
Listar grupos
GET /groupsCrear grupo
POST /groups{
"name": "Sucursal Centro",
"description": "Pantallas de la sucursal ubicada en Centro Historico",
"screen_ids": ["scr_abc123", "scr_def456"]
}Obtener grupo
GET /groups/{group_id}Actualizar grupo
PATCH /groups/{group_id}Eliminar grupo
DELETE /groups/{group_id}Codigos de respuesta
| Codigo | Descripcion |
|---|---|
200 | Solicitud exitosa |
201 | Recurso creado exitosamente |
204 | Recurso eliminado exitosamente |
400 | Solicitud mal formada |
401 | No autenticado |
403 | Sin permisos suficientes |
404 | Recurso no encontrado |
409 | Conflicto (ej: medio en uso al intentar eliminar) |
422 | Error de validacion |
429 | Limite de tasa excedido |
500 | Error interno del servidor |
Paginacion
Todos los endpoints de listado soportan paginacion. Usa los campos meta.current_page y meta.total_pages de la respuesta para navegar entre paginas. El maximo de resultados por pagina es 100.