---
name: lutrix
description: >-
  Cria, edita, exporta e gera imagens em lote (data-merge) no Lutrix — uma
  plataforma de design estilo Canva, feita para agentes — pela API REST ou pelo
  servidor MCP. Use quando o usuário quiser montar imagens/posts programaticamente
  a partir de um documento de design (JSON), preencher um template com dados para
  produzir várias peças de uma vez, exportar PNG/JPG/SVG/PDF, gerar imagens por IA,
  remover fundo, ou gerenciar projetos de design. A autenticação é uma API key por
  organização, enviada no header X-Api-Key.
license: MIT
metadata:
  homepage: https://lutrix.app
  docs: https://lutrix.app/docs
---

# Lutrix — criação de design via API/MCP

Lutrix é uma plataforma de design **API/MCP-first** (como o Canva, mas feita para
agentes de IA). Tudo que o editor visual faz também dá por HTTP.

## Modelo mental
- Hierarquia: **Organização → Workspaces → Projetos**.
- Um **projeto** guarda um **documento de design** (JSON): uma ou mais **páginas**,
  cada uma um canvas com uma lista de **nós** (texto, formas, imagens, vetores).
- A partir do projeto você **exporta** uma imagem (PNG/JPG/SVG/PDF) **ou** usa como
  **template** e faz **data-merge**: 1 imagem por linha de dados.
- Tudo é isolado por organização (multi-tenant). Uma API key só enxerga a própria org.

## Fluxo recomendado ao criar com IA
1. **Consulte a marca** — `lutrix_get_brand_kit` (ou GET /workspaces/:id/brand-kit/brief): baseie cores, fontes e voz na identidade do cliente. Para **configurar/atualizar** o kit (plano Estúdio), use `lutrix_set_brand_kit` — logos exigem `assetKey` (suba a imagem antes).
2. **Monte o design** — `lutrix_set_project_doc`.
3. **Mostre a prévia** — `lutrix_render_preview`: devolve a imagem (carimbada "Prévia"), **grátis**. **Exiba ao usuário** para ele aprovar antes de gastar crédito.
4. **Meça** — `GET .../measure` (grátis): as caixas REAIS de cada nó. É o passo que pega texto que não coube (quebrou ou vazou) e elementos sobrepostos — coisas que não dá para prever ao escrever o doc, porque dependem da fonte e do tracking. Corrija com os números e meça de novo.
5. **Audite** — `lutrix_preflight` (grátis): conserte os `warn` (fora da página, baixo contraste, cor/fonte fora do kit de marca).
6. **Só então exporte** — `lutrix_export_png`/exports: o export é o **único** passo que gasta **1 crédito por peça**.

> Prévia, medição e pré-voo **não gastam crédito** — itere à vontade; cobra-se só no export final aprovado. Geração de imagem por IA gasta crédito por tentativa (o prompt é do cliente).

## Setup
- **Base URL:** `https://lutrix-api-739d.onrender.com`
- **Auth:** envie o header `X-Api-Key: lutrix_sk_...` em TODA requisição. Crie uma
  chave no app em `https://lutrix.app/app` (painel *Chaves de API*) — ela aparece **uma vez só**.
  Sem chave / chave inválida → `401`.
- Corpos são JSON (`Content-Type: application/json`), exceto uploads de arquivo
  (`multipart/form-data`).

## Começo rápido (criar → preencher → exportar)
```bash
API="https://lutrix-api-739d.onrender.com"; KEY="lutrix_sk_..."
# 1. escolher um workspace existente
WS=$(curl -s $API/workspaces -H "X-Api-Key: $KEY" | jq -r '.[0].id')
# 2. criar um projeto 1080x1080
PID=$(curl -s -X POST $API/workspaces/$WS/projects \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"name":"Promo","width":1080,"height":1080}' | jq -r '.id')
# 3. definir o documento de design (texto com campo {{nome}})
curl -s -X PUT $API/workspaces/$WS/projects/$PID/doc \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/json" -d '{
    "schemaVersion":1,"width":1080,"height":1080,"background":"#0f172a",
    "nodes":[{"type":"text","id":"t1","x":80,"y":420,"width":920,"height":240,
      "text":"Olá {{nome}}","fontSize":96,"fill":"#ffffff","align":"center"}]}'
# 4a. exportar um PNG (1 crédito) → devolve uma URL assinada
curl -s -X POST $API/workspaces/$WS/projects/$PID/export -H "X-Api-Key: $KEY"
# 4b. OU gerar várias peças de uma vez (1 crédito por linha)
curl -s -X POST $API/workspaces/$WS/projects/$PID/merge \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"rows":[{"nome":"Ana"},{"nome":"Bruno"}]}'
```

## Endpoints (todos exigem X-Api-Key)

### Workspaces
- `GET  /workspaces` — lista
- `POST /workspaces` — `{ name }` (mín. 2 caracteres)
- `GET  /workspaces/role` — seu papel na org
- `DELETE /workspaces/:wid` — exclui + projetos em cascata (admin)

### Projetos
- `GET  /workspaces/:wid/projects` — lista (id, nome, tags, tamanho, updatedAt)
- `POST /workspaces/:wid/projects` — `{ name, width?, height?, background?, tags? }`
- `GET  /workspaces/:wid/projects/:pid` — inclui o documento de design (`doc`)
- `PATCH /workspaces/:wid/projects/:pid` — `{ name?, tags? }`
- `DELETE /workspaces/:wid/projects/:pid` — exclui
- `PUT  /workspaces/:wid/projects/:pid/doc` — substitui o doc (corpo = documento)
- `POST /workspaces/:wid/projects/:pid/export` — renderiza PNG → `{ url }` (1 crédito)
- `POST /workspaces/:wid/projects/:pid/exports` — `{ format:"png|jpg|svg|pdf", pageIds? }` → `{ url }` ou `{ files:[...] }` (1 crédito/página)
- `GET  /workspaces/:wid/projects/:pid/fields` — campos `{{...}}` do template → `{ fields:[] }`
- `POST /workspaces/:wid/projects/:pid/merge` — `{ rows:[{ campo:valor }] }` → `{ results:[{ index, url }] }` (1 crédito/linha)
- `POST /workspaces/:wid/projects/:pid/preview` — prévia low-res (carimbo "Prévia") → `{ url }` — GRÁTIS. Mostre ao usuário antes de exportar.
- `GET  /workspaces/:wid/projects/:pid/preflight` — audita o design antes de exportar → `{ ok, checks:[{ level, code, message, nodeId? }] }` — GRÁTIS
- `GET  /workspaces/:wid/projects/:pid/measure?pageId=` — mede a página com o MOTOR DE DESENHO → `{ pageId, width, height, boxes:[{ id, type, x, y, width, height, lines?, overflow? }], warnings:[{ kind, nodeId, otherId?, message }] }` — GRÁTIS.
  A caixa final de um texto depende da fonte carregada, do tracking e da quebra por largura — não dá para prever contando caracteres. Peça a medida, corrija com números e só então exporte. `kind`: `overflow` (o texto não coube: quebrou em mais linhas ou vazou), `collision` (dois textos se sobrepõem), `offcanvas` (saiu da página).

### Marca (kit de marca)
- `GET  /workspaces/:wid/brand-kit` — kit do workspace (cores/fontes/logos/voz)
- `PUT  /workspaces/:wid/brand-kit` — `{ colors, fonts, logos, voice }` (feature do Estúdio → 402 no Ateliê)
- `GET  /workspaces/:wid/brand-kit/brief` — brief legível pela IA (paleta, fontes, voz + texto pronto p/ o contexto)

### Assets & IA
- `POST /assets` — upload multipart (png/jpg/webp/gif/svg) → `{ assetKey, src }`
- `POST /assets/from-url` — `{ url }` → `{ assetKey, src }`
- `GET  /assets/ai/models` — modelos de IA + custo em créditos por tamanho
- `POST /assets/generate` — `{ model, prompt, width, height, inputImageUrl? }` → `{ assetKey, src }`
- `POST /assets/remove-background` — `{ imageUrl }` → `{ assetKey, src }` (5 créditos)
- `GET  /assets/stock/photos?source=unsplash|pexels&q=` — busca fotos de stock
- `GET  /assets/stock/icons?q=` — busca ícones (Iconify)
- `POST /assets/stock/pick` — `{ source, url, downloadLocation? }` — salva um item de stock como asset
- `GET|POST /assets/folders`, `DELETE /assets/folders/:id` — pastas da biblioteca
- `GET /assets/library`, `POST /assets/library` (multipart), `PATCH /assets/library/:id` `{ folderId }`, `DELETE /assets/library/:id`
- `GET|POST /fonts` (multipart ttf/otf/woff/woff2), `DELETE /fonts/:id`

### Conta
- `GET /credits` → `{ balance }`
- `GET /templates` → documentos de design prontos (público)
- `GET|POST /api-keys`, `DELETE /api-keys/:id` (admin)

## Documento de design (schema)
No `PUT .../doc` são aceitas duas formas (ambas normalizadas para v2 na leitura):

**v1 (página única):**
```json
{ "schemaVersion":1, "width":1080, "height":1080, "background":"#ffffff", "nodes":[ ... ] }
```
**v2 (multi-página):**
```json
{ "schemaVersion":2, "layout":"strip", "pages":[
  { "id":"p1", "width":1080, "height":1080, "background":"#ffffff", "x":0, "y":0, "nodes":[ ... ] }
]}
```

**Campos comuns de todo nó:** `id` (string, obrigatório), `x`, `y`, `width`,
`height` (números), `rotation?`, `opacity?` (0–1), `name?`, `hidden?`, `locked?`,
sombra (`shadowColor?`, `shadowBlur?`, `shadowOffsetX?`, ...), `blur?`.

### Layout assistido (evita fazer aritmética de posição)
Montar peça por API significa calcular `x`/`y` de cada elemento, e é aí que nascem os
defeitos clássicos: quatro pontos de partida diferentes na mesma página, e elementos que se
encavalam porque o texto de cima cresceu. Dois atalhos evitam isso:

- **`page.columns`** (array de `x` em px) + **`col`** no nó → o nó recebe `x = columns[col]`.
  Em vez de digitar `x` livre, escolha uma coluna: tudo na página parte dos mesmos pontos.
- **`stackAfter`** (id de outro nó) + **`stackGap?`** (px, default 24) → o `y` do nó vira o
  rodapé do nó referenciado + o respiro. **A altura considerada é a real** — se o texto de cima
  quebrar em duas linhas, o de baixo desce junto.

```json
{ "id":"p1", "width":1080, "height":1080, "background":"#0B0F17", "x":0, "y":0,
  "columns":[80, 314, 560],
  "nodes":[
    { "id":"rotulo", "type":"text", "text":"25 EMPRESAS PEDIRAM", "col":0, "x":0, "y":402,
      "width":760, "height":36, "fontSize":28 },
    { "id":"titulo", "type":"text", "text":"O que elas querem", "col":0,
      "stackAfter":"rotulo", "stackGap":16, "x":0, "y":0, "width":920, "height":96, "fontSize":80 }
  ]}
```

Resolvidos **no save**: o documento gravado volta com `x`/`y` absolutos e sem essas props.
São açúcar de escrita, não estado — mudar `columns` depois não reposiciona o que já foi salvo.

**Tipos de nó:**
- `text` — `text`, `fontSize?`, `fontFamily?`, `fontStyle?` (normal|bold|italic|italic bold),
  `fill?`, `align?` (left|center|right), `lineHeight?`, `wrap?` (`word` = quebra em palavras,
  o padrão; `none` = não quebra e transborda a caixa). Use `{{campo}}` dentro de `text` para data-merge.
- `rect` — `fill`, `fillGradient?`, `cornerRadius?`, `stroke?`, `strokeWidth?`.
- `ellipse` / `triangle` — `fill`, `fillGradient?`, `stroke?`, `strokeWidth?`.
- `path` — `d` (path SVG em coords do viewBox), `viewWidth`, `viewHeight`, `fill`, `stroke?`,
  `strokeWidth?`. O render escala `d` para `width`×`height`.
- `image` — `assetKey` (de um upload/generate/from-url), `src` (URL assinada), `crop?`,
  `flipX?`, `flipY?`, `field?` (data-merge: cada linha fornece o assetKey desta imagem).
- `draw` — traço livre: `points` (achatado `[x0,y0,...]`), `stroke`, `strokeWidth`, `tension?`, `lineCap?`.

**`background` e `fillGradient`** podem ser uma string hex OU
`{ "type":"linear", "angle":90, "stops":[{ "color":"#fff", "at":0 }, ...] }`
ou `{ "type":"radial", "stops":[...] }`.

## Data-merge (geração em lote)
Coloque marcadores `{{campo}}` em nós de texto (ou `field` num nó de imagem).
`GET .../fields` lista os marcadores encontrados. `POST .../merge` com `rows`
devolve uma imagem renderizada por linha.

## Imagens por IA
- `GET /assets/ai/models` devolve os modelos (texto→imagem e edição) com o custo em
  créditos por tamanho. Mais barato: `flux-schnell`.
- Texto→imagem: `POST /assets/generate { model, prompt, width, height }`.
- Edição de imagem (modelos `mode: "edit"`): passe também `inputImageUrl`.
- Remover fundo: `POST /assets/remove-background { imageUrl }`.
Todos devolvem `{ assetKey, src }` — use em um nó `image`.

## Créditos
export 1 · exports 1/página · merge 1/peça · remover fundo 5 · generate = por
modelo/tamanho (ver `/assets/ai/models`) · importar arquivo 2. Toda org nova começa
com **200**. Saldo em `GET /credits`.

## MCP (para agentes compatíveis com MCP)
Rode o servidor MCP do Lutrix (stdio) e configure o cliente:
```json
{
  "mcpServers": {
    "lutrix": {
      "command": "node",
      "args": ["/caminho/lutrix-mcp-server/dist/index.js"],
      "env": {
        "LUTRIX_API_URL": "https://lutrix-api-739d.onrender.com",
        "LUTRIX_API_KEY": "lutrix_sk_..."
      }
    }
  }
}
```
**15 tools:** lutrix_list_workspaces, lutrix_create_workspace, lutrix_list_projects, lutrix_create_project, lutrix_update_project, lutrix_get_project, lutrix_get_brand_kit, lutrix_set_brand_kit, lutrix_set_project_doc, lutrix_render_preview, lutrix_preflight, lutrix_export_png, lutrix_list_template_fields, lutrix_merge, lutrix_upload_asset_from_url.

## Regras para agentes
- Sempre envie `X-Api-Key`. **Nunca** exponha a chave no frontend nem em logs.
- Reaproveite um workspace existente (`GET /workspaces`) em vez de criar novos à toa.
- Depois de `generate`/`upload`/`from-url`, use o `assetKey` **e** o `src` retornados
  num nó `image`; o `src` é re-assinado no `GET` do projeto e no export.
- Chamadas que gastam créditos (export, exports, merge, generate, remove-background)
  custam créditos reais — **confirme com o usuário** antes de lotes grandes.
