Proyectos
Tus diseños. Cada proyecto tiene de 1 a 3 páginas; cada página guarda sus objetos de Fabric.js (textos, formas, imágenes) en objects. GET devuelve una cabecera ETag: envíala en If-Match al guardar y, si el proyecto cambió mientras tanto, la API responde 412 en vez de sobrescribirlo. Abre cualquier proyecto en el editor con https://creavibe.app/creador/?proyecto={id}.
| Endpoint | Descripción |
|---|---|
GET /projects | Listar proyectos |
POST /projects | Crear un proyecto |
GET /projects/{id} | Obtener un proyecto |
PUT /projects/{id} | Guardar un proyecto |
PATCH /projects/{id} | Actualizar un proyecto |
Listar proyectos
/projectsDevuelve tus proyectos, del más reciente al más antiguo.
Parámetros de consulta
| Nombre | Tipo | Descripción |
|---|---|---|
q | texto | Busca en el nombre. |
period | texto | Última edición: today, 7d, 30d u older. |
page | entero | Página, desde 1. |
page_size | entero | Resultados por página (24 por defecto, máximo 100). |
Ejemplo
curl "https://creavibe.app/api/v1/projects?page_size=2" \
-H "Authorization: Bearer cv_TU_TOKEN"const respuesta = await fetch('https://creavibe.app/api/v1/projects?page_size=2', {
method: 'GET',
headers: {
Authorization: 'Bearer cv_TU_TOKEN',
},
});
const datos = await respuesta.json();import requests
respuesta = requests.get(
"https://creavibe.app/api/v1/projects?page_size=2",
headers={"Authorization": "Bearer cv_TU_TOKEN"},
)
datos = respuesta.json(){
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "63af0738-62c4-433d-bfa1-8517ed886c71",
"name": "Demo sangre",
"thumbnail_url": null,
"page_count": 1,
"template": "demo-sangre",
"created_at": "2026-10-12T10:11:11.090Z",
"updated_at": "2026-10-12T10:11:11.090Z"
}
]
}Crear un proyecto
/projectsCrea un proyecto a partir de una plantilla (template), desde cero (pages) o como copia de otro tuyo (source_project_id). Al usar una plantilla, sus imágenes pasan a tu biblioteca. En el ejemplo, objects aparece resumido.
Cuerpo (JSON)
| Nombre | Tipo | Descripción |
|---|---|---|
template | texto | Slug de una plantilla. |
pages | lista | De 1 a 3 páginas: name, width, height, background, x, y y objects. |
source_project_id | uuid | Duplica uno de tus proyectos. |
name | texto | Nombre del proyecto. |
Ejemplo
curl -X POST "https://creavibe.app/api/v1/projects" \
-H "Authorization: Bearer cv_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template":"demo-sangre"}'const respuesta = await fetch('https://creavibe.app/api/v1/projects', {
method: 'POST',
headers: {
Authorization: 'Bearer cv_TU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"template": "demo-sangre"
}),
});
const datos = await respuesta.json();import requests
respuesta = requests.post(
"https://creavibe.app/api/v1/projects",
headers={"Authorization": "Bearer cv_TU_TOKEN"},
json={
"template": "demo-sangre"
},
)
datos = respuesta.json()Location: /api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71
ETag: "1791799871090749"{
"id": "63af0738-62c4-433d-bfa1-8517ed886c71",
"name": "Demo sangre",
"template": "demo-sangre",
"thumbnail_url": null,
"pages": [
{
"name": "Demo sangre",
"width": 1080,
"height": 1080,
"background": "#FFFFFF",
"x": 80,
"y": 80,
"objects": [
{
"rx": 0,
"ry": 0,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "#FFFFFF",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"type": "artboard",
"id": "ab-1"
}
},
{
"fontSize": 175,
"fontWeight": "bold",
"fontFamily": "Bowlby One",
"fontStyle": "normal",
"lineHeight": 0.75,
"text": "ANIMALES\nCON\nCARNE",
"charSpacing": -70,
"textAlign": "left",
"styles": [],
"pathStartOffset": 0,
"pathSide": "left",
"pathAlign": "baseline",
"underline": false,
"overline": false,
"linethrough": false,
"textBackgroundColor": "",
"direction": "ltr",
"textDecorationThickness": 66.667,
"minWidth": 20,
"splitByGrapheme": false,
"type": "Textbox",
"version": "7.2.0",
"originX": "center",
"originY": "center",
"left": 590.9644,
"top": 347.0568,
"width": 968.1643,
"height": 494.375,
"fill": "#000000",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": true,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "stroke",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"clipPath": {
"rx": 0,
"ry": 0,
"inverted": false,
"absolutePositioned": true,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "rgb(0,0,0)",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"abId": "ab-1"
}
},
"data": {
"type": "text",
"artboardId": "ab-1",
"autoWidth": false
}
}
]
}
],
"created_at": "2026-10-12T10:11:11.090Z",
"updated_at": "2026-10-12T10:11:11.090Z"
}Obtener un proyecto
/projects/{id}Devuelve un proyecto con todas sus páginas y, en la cabecera ETag, su versión. En el ejemplo, objects aparece resumido.
Parámetros de la ruta
| Nombre | Tipo | Descripción |
|---|---|---|
idobligatorio | uuid | Id del proyecto. |
Ejemplo
curl "https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71" \
-H "Authorization: Bearer cv_TU_TOKEN"const respuesta = await fetch('https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71', {
method: 'GET',
headers: {
Authorization: 'Bearer cv_TU_TOKEN',
},
});
const datos = await respuesta.json();import requests
respuesta = requests.get(
"https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71",
headers={"Authorization": "Bearer cv_TU_TOKEN"},
)
datos = respuesta.json()ETag: "1791799871090749"{
"id": "63af0738-62c4-433d-bfa1-8517ed886c71",
"name": "Demo sangre",
"template": "demo-sangre",
"thumbnail_url": null,
"pages": [
{
"name": "Demo sangre",
"width": 1080,
"height": 1080,
"background": "#FFFFFF",
"x": 80,
"y": 80,
"objects": [
{
"rx": 0,
"ry": 0,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "#FFFFFF",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"type": "artboard",
"id": "ab-1"
}
},
{
"fontSize": 175,
"fontWeight": "bold",
"fontFamily": "Bowlby One",
"fontStyle": "normal",
"lineHeight": 0.75,
"text": "ANIMALES\nCON\nCARNE",
"charSpacing": -70,
"textAlign": "left",
"styles": [],
"pathStartOffset": 0,
"pathSide": "left",
"pathAlign": "baseline",
"underline": false,
"overline": false,
"linethrough": false,
"textBackgroundColor": "",
"direction": "ltr",
"textDecorationThickness": 66.667,
"minWidth": 20,
"splitByGrapheme": false,
"type": "Textbox",
"version": "7.2.0",
"originX": "center",
"originY": "center",
"left": 590.9644,
"top": 347.0568,
"width": 968.1643,
"height": 494.375,
"fill": "#000000",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": true,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "stroke",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"clipPath": {
"rx": 0,
"ry": 0,
"inverted": false,
"absolutePositioned": true,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "rgb(0,0,0)",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"abId": "ab-1"
}
},
"data": {
"type": "text",
"artboardId": "ab-1",
"autoWidth": false
}
}
]
}
],
"created_at": "2026-10-12T10:11:11.090Z",
"updated_at": "2026-10-12T10:11:11.090Z"
}Guardar un proyecto
/projects/{id}Sustituye el nombre y todas las páginas (hasta 3 páginas y 2 MB por página). Lo habitual es obtenerlo, cambiar lo necesario y enviarlo completo con If-Match.
Parámetros de la ruta
| Nombre | Tipo | Descripción |
|---|---|---|
idobligatorio | uuid | Id del proyecto. |
Cuerpo (JSON)
| Nombre | Tipo | Descripción |
|---|---|---|
nameobligatorio | texto | Nombre del proyecto. |
pagesobligatorio | lista | Todas las páginas. |
Ejemplo
curl -X PUT "https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71" \
-H "Authorization: Bearer cv_TU_TOKEN" \
-H 'If-Match: "1791799871090749"' \
-H "Content-Type: application/json" \
-d '{"name":"Launch","pages":[{"name":"Portada","width":1080,"height":1350,"background":"#FFFFFF","x":0,"y":0,"objects":[{"type":"Textbox","text":"Hola","left":120,"top":160,"fontSize":96,"fontFamily":"Anton","fill":"#111111"}]}]}'const respuesta = await fetch('https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71', {
method: 'PUT',
headers: {
Authorization: 'Bearer cv_TU_TOKEN',
'If-Match': '"1791799871090749"',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Launch",
"pages": [
{
"name": "Portada",
"width": 1080,
"height": 1350,
"background": "#FFFFFF",
"x": 0,
"y": 0,
"objects": [
{
"type": "Textbox",
"text": "Hola",
"left": 120,
"top": 160,
"fontSize": 96,
"fontFamily": "Anton",
"fill": "#111111"
}
]
}
]
}),
});
const datos = await respuesta.json();import requests
respuesta = requests.put(
"https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71",
headers={"Authorization": "Bearer cv_TU_TOKEN", "If-Match": '"1791799871090749"'},
json={
"name": "Launch",
"pages": [
{
"name": "Portada",
"width": 1080,
"height": 1350,
"background": "#FFFFFF",
"x": 0,
"y": 0,
"objects": [
{
"type": "Textbox",
"text": "Hola",
"left": 120,
"top": 160,
"fontSize": 96,
"fontFamily": "Anton",
"fill": "#111111"
}
]
}
]
},
)
datos = respuesta.json()ETag: "1791799871111973"{
"id": "63af0738-62c4-433d-bfa1-8517ed886c71",
"name": "Launch",
"template": "demo-sangre",
"thumbnail_url": null,
"pages": [
{
"name": "Demo sangre",
"width": 1080,
"height": 1080,
"background": "#FFFFFF",
"x": 80,
"y": 80,
"objects": [
{
"rx": 0,
"ry": 0,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "#FFFFFF",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"type": "artboard",
"id": "ab-1"
}
},
{
"fontSize": 175,
"fontWeight": "bold",
"fontFamily": "Bowlby One",
"fontStyle": "normal",
"lineHeight": 0.75,
"text": "ANIMALES\nCON\nCARNE",
"charSpacing": -70,
"textAlign": "left",
"styles": [],
"pathStartOffset": 0,
"pathSide": "left",
"pathAlign": "baseline",
"underline": false,
"overline": false,
"linethrough": false,
"textBackgroundColor": "",
"direction": "ltr",
"textDecorationThickness": 66.667,
"minWidth": 20,
"splitByGrapheme": false,
"type": "Textbox",
"version": "7.2.0",
"originX": "center",
"originY": "center",
"left": 590.9644,
"top": 347.0568,
"width": 968.1643,
"height": 494.375,
"fill": "#000000",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": true,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "stroke",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"clipPath": {
"rx": 0,
"ry": 0,
"inverted": false,
"absolutePositioned": true,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "rgb(0,0,0)",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"abId": "ab-1"
}
},
"data": {
"type": "text",
"artboardId": "ab-1",
"autoWidth": false
}
}
]
}
],
"created_at": "2026-10-12T10:11:11.090Z",
"updated_at": "2026-10-12T10:11:11.111Z"
}Actualizar un proyecto
/projects/{id}Cambia solo lo que envíes (JSON Merge Patch): name y/o pages. Renombrar sin enviar páginas renombra también la primera. Acepta If-Match.
Parámetros de la ruta
| Nombre | Tipo | Descripción |
|---|---|---|
idobligatorio | uuid | Id del proyecto. |
Cuerpo (JSON)
| Nombre | Tipo | Descripción |
|---|---|---|
name | texto | Nombre nuevo. |
pages | lista | Páginas nuevas (todas). |
Ejemplo
curl -X PATCH "https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71" \
-H "Authorization: Bearer cv_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Launch (final)"}'const respuesta = await fetch('https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71', {
method: 'PATCH',
headers: {
Authorization: 'Bearer cv_TU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Launch (final)"
}),
});
const datos = await respuesta.json();import requests
respuesta = requests.patch(
"https://creavibe.app/api/v1/projects/63af0738-62c4-433d-bfa1-8517ed886c71",
headers={"Authorization": "Bearer cv_TU_TOKEN"},
json={
"name": "Launch (final)"
},
)
datos = respuesta.json()ETag: "1791799871120847"{
"id": "63af0738-62c4-433d-bfa1-8517ed886c71",
"name": "Launch (final)",
"template": "demo-sangre",
"thumbnail_url": null,
"pages": [
{
"name": "Launch (final)",
"width": 1080,
"height": 1080,
"background": "#FFFFFF",
"x": 80,
"y": 80,
"objects": [
{
"rx": 0,
"ry": 0,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "#FFFFFF",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"type": "artboard",
"id": "ab-1"
}
},
{
"fontSize": 175,
"fontWeight": "bold",
"fontFamily": "Bowlby One",
"fontStyle": "normal",
"lineHeight": 0.75,
"text": "ANIMALES\nCON\nCARNE",
"charSpacing": -70,
"textAlign": "left",
"styles": [],
"pathStartOffset": 0,
"pathSide": "left",
"pathAlign": "baseline",
"underline": false,
"overline": false,
"linethrough": false,
"textBackgroundColor": "",
"direction": "ltr",
"textDecorationThickness": 66.667,
"minWidth": 20,
"splitByGrapheme": false,
"type": "Textbox",
"version": "7.2.0",
"originX": "center",
"originY": "center",
"left": 590.9644,
"top": 347.0568,
"width": 968.1643,
"height": 494.375,
"fill": "#000000",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": true,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "stroke",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"clipPath": {
"rx": 0,
"ry": 0,
"inverted": false,
"absolutePositioned": true,
"type": "Rect",
"version": "7.2.0",
"originX": "left",
"originY": "top",
"left": 80,
"top": 80,
"width": 1080,
"height": 1080,
"fill": "rgb(0,0,0)",
"stroke": null,
"strokeWidth": 1,
"strokeDashArray": null,
"strokeLineCap": "butt",
"strokeDashOffset": 0,
"strokeLineJoin": "miter",
"strokeUniform": false,
"strokeMiterLimit": 4,
"scaleX": 1,
"scaleY": 1,
"angle": 0,
"flipX": false,
"flipY": false,
"opacity": 1,
"shadow": null,
"visible": true,
"backgroundColor": "",
"fillRule": "nonzero",
"paintFirst": "fill",
"globalCompositeOperation": "source-over",
"skewX": 0,
"skewY": 0,
"data": {
"abId": "ab-1"
}
},
"data": {
"type": "text",
"artboardId": "ab-1",
"autoWidth": false
}
}
]
}
],
"created_at": "2026-10-12T10:11:11.090Z",
"updated_at": "2026-10-12T10:11:11.120Z"
}