Manual de uso del API de Portafolio (solo lectura)
El API de portafolio expone un endpoint de solo lectura para consultar los trabajos publicados (casos de estudio) de tu workspace. Vive en /api/portfolio y devuelve JSON.
Autenticación
- Incluye
Authorization: Bearer <token>en cada solicitud. - El token debe estar activo y tener permisos sobre el recurso que consultas.
- El workspace se determina siempre desde el token; nunca lo envías en la solicitud.
Permisos
read: permite ejecutar peticionesGET.
Si el token está vencido, inactivo o carece del permiso read, la respuesta será 401 o 403.
Códigos de respuesta comunes
200 OK: respuesta exitosa.400 Bad Request: parámetros inválidos.401 / 403: token ausente, inválido o sin permisos.404 Not Found: trabajo inexistente o no publicado.405 Method Not Allowed: se intentó un método distinto deGET.500 Internal Server Error: error no controlado en el servidor.
Operaciones — /api/portfolio
| Operación | Método y ruta | Descripción |
|---|---|---|
| Listado | GET /api/portfolio | Trabajos publicados, ordenados por fecha de publicación descendente. No incluye content. |
| Detalle | GET /api/portfolio?slug=<slug> | Un trabajo publicado, con content (html y htmlPreview). Cada consulta suma una vista a viewCount. |
GET listado
Query params
category(string, opcional): devuelve solo trabajos de esa categoría. La comparación no distingue mayúsculas de minúsculas (Brandingybrandingson equivalentes).limit(número, opcional): máximo de resultados (1–100). Por defecto50.
Ejemplo listado básico
curl "https://cms.begraffic.com/api/portfolio" \
-H "Authorization: Bearer TU_TOKEN"Ejemplo con filtros
curl "https://cms.begraffic.com/api/portfolio?category=branding&limit=10" \
-H "Authorization: Bearer TU_TOKEN"Respuesta
{
"count": 1,
"items": [
{
"id": "rebranding-acme",
"title": "Rebranding Acme",
"slug": "rebranding-acme",
"status": "published",
"client": "Acme Corp",
"category": "Branding",
"projectDate": "2024-03-01T00:00:00.000Z",
"projectUrl": "https://acme.com",
"services": ["Identidad visual", "Diseño web"],
"excerpt": "Renovación completa de la identidad de Acme.",
"coverImage": {
"previewUrl": "https://cdn.example.com/portadas/acme.jpg",
"url": "https://cdn.example.com/portadas/acme.jpg",
"variants": {
"original": { "url": "https://cdn.example.com/portadas/acme.jpg", "width": 1920, "height": 1080 },
"medium": { "url": "https://cdn.example.com/portadas/acme-md.jpg", "width": 960, "height": 540 },
"small": { "url": "https://cdn.example.com/portadas/acme-sm.jpg", "width": 480, "height": 270 },
"thumbnail": { "url": "https://cdn.example.com/portadas/acme-th.jpg", "width": 160, "height": 90 }
}
},
"viewCount": 42,
"publishedAt": "2024-05-01T10:00:00.000Z",
"createdAt": "2024-04-20T09:00:00.000Z",
"updatedAt": "2024-05-02T12:30:00.000Z"
}
]
}Notas del listado:
- Solo se incluyen trabajos con
status: published. - El campo
contentse omite en el listado para reducir el tamaño de la respuesta; solo está disponible en el endpoint de detalle. coverImagesiempre llega conpreviewUrl,urly las cuatro variantes (original,medium,small,thumbnail), cada una con suurlgarantizado; si el trabajo no tiene portada, esnull.
GET detalle
GET /api/portfolio?slug=<slug>
Devuelve un trabajo publicado que coincida con el slug. Si existe pero no está en estado published, la respuesta será 404. Este endpoint incluye el campo content y suma una vista al contador viewCount.
Ejemplo
curl "https://cms.begraffic.com/api/portfolio?slug=rebranding-acme" \
-H "Authorization: Bearer TU_TOKEN"Respuesta
{
"item": {
"id": "rebranding-acme",
"title": "Rebranding Acme",
"slug": "rebranding-acme",
"status": "published",
"client": "Acme Corp",
"category": "Branding",
"projectDate": "2024-03-01T00:00:00.000Z",
"projectUrl": "https://acme.com",
"services": ["Identidad visual", "Diseño web"],
"excerpt": "Renovación completa de la identidad de Acme.",
"coverImage": {
"previewUrl": "https://cdn.example.com/portadas/acme.jpg",
"url": "https://cdn.example.com/portadas/acme.jpg",
"variants": {
"original": { "url": "https://cdn.example.com/portadas/acme.jpg", "width": 2400, "height": 1350 },
"medium": { "url": "https://cdn.example.com/portadas/acme-md.jpg", "width": 1200, "height": 675 },
"small": { "url": "https://cdn.example.com/portadas/acme-sm.jpg", "width": 600, "height": 338 },
"thumbnail": { "url": "https://cdn.example.com/portadas/acme-th.jpg", "width": 300, "height": 169 }
}
},
"content": {
"html": "<h1>Rebranding Acme</h1><p>El reto...</p>",
"htmlPreview": "<h1>Rebranding Acme</h1>"
},
"viewCount": 43,
"publishedAt": "2024-05-01T10:00:00.000Z",
"createdAt": "2024-04-20T09:00:00.000Z",
"updatedAt": "2024-05-02T12:30:00.000Z"
}
}El endpoint de detalle devuelve el contenido en content, con los campos html (la página completa del caso de estudio) y htmlPreview (un extracto para vistas previas).
Buenas prácticas
- Normaliza slugs a minúsculas antes de consultarlos.
- Maneja específicamente los códigos
404(trabajo no publicado) y405(método no permitido) en tus integraciones. - Usa las variantes de
coverImagesegún el contexto (thumbnailpara listados,mediumuoriginalpara la página del caso de estudio). - Si llegas a necesitar operaciones de escritura, deberás coordinar con el equipo para habilitar endpoints adicionales.