# API de conteúdo — cheg.ai

Base URL: `https://blog.cheg.ai`
Tenant: resolvido pelo header `Host` (este domínio = site `chegai`).

## Autenticação

```
Authorization: Bearer <CONTENT_API_KEY_CHEGAI>
```

Keys são configuradas no Portainer / env do container. Nunca envie a key em query string.

## Endpoints

### `GET /api/v1/docs`
Documentação desta API (Markdown). **Público.**

### `GET /api/v1/openapi.json`
Especificação OpenAPI 3.0. **Público.**

### `GET /api/v1/posts`
Lista posts do tenant (inclui `public`, `unlisted` e `draft`). **Auth obrigatória.**

### `POST /api/v1/posts`
Cria post. **409** se o slug já existir. **Auth obrigatória.**

### `GET /api/v1/posts/{slug}`
Lê um post (frontmatter + body). **Auth obrigatória.**

### `PUT /api/v1/posts/{slug}`
Upsert (cria ou atualiza). O slug da URL prevalece. **Auth obrigatória.**

### `DELETE /api/v1/posts/{slug}`
Remove o arquivo MDX. **Auth obrigatória.**

## Visibilidade (landings)

| `visibility` | Home / RSS / sitemap / llms | URL direta `/posts/{slug}` |
|----------------|-----------------------------|-----------------------------|
| `public` | sim | sim |
| `unlisted` | **não** (landing) | **sim** |
| `draft` | não | não (prod); sim na API / dev |

`draft: true` (legado) equivale a `visibility: "draft"`.
Sem `visibility` e `draft: false` → `public`.

## Landings (`visibility: "unlisted"`)

Layout de marketing (hero + CTAs), não de artigo. Campos opcionais:

| Campo | Uso |
|-------|-----|
| eyebrow | Label acima do título |
| ctaLabel / ctaHref | CTA primário do hero e rodapé |
| ctaSecondaryLabel / ctaSecondaryHref | CTA secundário |
| ctaFooterTitle / ctaFooterDescription | Faixa final de conversão |
| cover | Imagem do hero |

Componentes MDX no `body`:

```mdx
<CTAGroup>
  <CTA href="https://cheg.ai" variant="primary">Agendar demo</CTA>
  <CTA href="#detalhes" variant="ghost">Ver detalhes</CTA>
</CTAGroup>

<Callout title="Por que agora" tone="accent">
Texto de reforço da oferta.
</Callout>

<FeatureGrid>
  <Feature title="Governança">Controle e auditoria.</Feature>
  <Feature title="Agentes">Marketplace pronto.</Feature>
</FeatureGrid>

<Stats>
  <Stat value="50%" label="Menos atrito" />
  <Stat value="4x" label="Mais velocidade" />
</Stats>
```

Variantes de `CTA`: `primary` | `secondary` | `ghost`.

### `GET /api/v1/media`
Lista imagens do tenant. **Auth obrigatória.**

### `POST /api/v1/media`
Upload multipart (`file`). Tipos: jpeg, png, gif, webp. Máx. 5 MB. **Auth obrigatória.**

### `DELETE /api/v1/media/{filename}`
Remove arquivo de mídia. **Auth obrigatória.**

### `GET /media/{filename}`
Serve a imagem publicamente (sem auth). Use a URL retornada no upload dentro do Markdown:

```md
![Legenda](https://blog.cheg.ai/media/1739-abc-foto.jpg)
```

## Body (POST / PUT)

```json
{
  "title": "Título do artigo",
  "description": "Resumo curto (SEO / llms.txt)",
  "date": "2026-07-22",
  "author": "Chegai",
  "tags": ["tag-a", "tag-b"],
  "slug": "meu-artigo",
  "visibility": "public",
  "draft": false,
  "cover": "https://blog.cheg.ai/media/capa.jpg",
  "body": "## Seção\n\nConteúdo em Markdown/MDX."
}
```

| Campo | Tipo | Regras |
|-------|------|--------|
| title | string | 1–200 |
| description | string | 1–500 |
| date | string | ISO ou data legível |
| author | string | 1–120 |
| tags | string[] | opcional |
| slug | string | kebab-case `[a-z0-9-]+` |
| visibility | string | `public` \| `unlisted` \| `draft` (default `public`) |
| draft | boolean | legado; `true` ⇒ draft |
| body | string | Markdown/MDX, obrigatório |
| cover | string | opcional — URL `https://…` ou path `/media/….jpg` (OG + capa) |

No Markdown do body:

```md
![Legenda da figura](/media/1739-abc-foto.jpg)
```

## Exemplos

```bash
# Criar
curl -s -X POST https://blog.cheg.ai/api/v1/posts \
  -H "Authorization: Bearer $CONTENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Meu artigo",
    "description": "Resumo",
    "date": "2026-07-22",
    "author": "Chegai",
    "tags": ["api"],
    "slug": "meu-artigo",
    "visibility": "public",
    "draft": false,
    "cover": "https://blog.cheg.ai/media/capa.jpg",
    "body": "## Olá\n\nTexto.\n\n![Figura](https://blog.cheg.ai/media/figura.jpg)"
  }'

# Landing page (unlisted — não aparece na home)
curl -s -X POST https://blog.cheg.ai/api/v1/posts \
  -H "Authorization: Bearer $CONTENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Operacione agentes com governança",
    "description": "Plataforma Chegai para times que precisam de IA com controle.",
    "date": "2026-07-22",
    "author": "Chegai",
    "tags": ["landing"],
    "slug": "campanha-agentes",
    "visibility": "unlisted",
    "eyebrow": "Produto",
    "ctaLabel": "Agendar demo",
    "ctaHref": "https://cheg.ai",
    "ctaSecondaryLabel": "Ver plataforma",
    "ctaSecondaryHref": "https://cheg.ai",
    "ctaFooterTitle": "Comece com a Chegai",
    "ctaFooterDescription": "Fale com um especialista e veja agentes em produção.",
    "body": "## O que você ganha\n\n<FeatureGrid>\n  <Feature title=\"Governança\">Aprovações e trilha de auditoria.</Feature>\n  <Feature title=\"Velocidade\">Do briefing ao agente em dias.</Feature>\n</FeatureGrid>\n\n<CTAGroup>\n  <CTA href=\"https://cheg.ai\" variant=\"primary\">Falar com especialista</CTA>\n</CTAGroup>"
  }'

# Listar
curl -s https://blog.cheg.ai/api/v1/posts \
  -H "Authorization: Bearer $CONTENT_API_KEY"

# Upsert
curl -s -X PUT https://blog.cheg.ai/api/v1/posts/meu-artigo \
  -H "Authorization: Bearer $CONTENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

# Remover
curl -s -X DELETE https://blog.cheg.ai/api/v1/posts/meu-artigo \
  -H "Authorization: Bearer $CONTENT_API_KEY"

# Upload de imagem
curl -s -X POST https://blog.cheg.ai/api/v1/media \
  -H "Authorization: Bearer $CONTENT_API_KEY" \
  -F "file=@./foto.jpg"

# Listar mídias
curl -s https://blog.cheg.ai/api/v1/media \
  -H "Authorization: Bearer $CONTENT_API_KEY"
```

## Respostas de erro

```json
{ "error": { "code": "unauthorized|validation_error|conflict|not_found|rate_limited|invalid_json", "message": "..." } }
```

| HTTP | Código |
|------|--------|
| 400 | validation_error, invalid_json |
| 401 | unauthorized |
| 404 | not_found |
| 409 | conflict |
| 429 | rate_limited |

## Persistência

Posts são gravados como `.mdx` em disco (volume bind no host).  
Após mutação, home, post, sitemap, rss e llms.* são revalidados.

## Artefatos públicos (sem auth)

- https://blog.cheg.ai/llms.txt
- https://blog.cheg.ai/llms-full.txt
- https://blog.cheg.ai/rss.xml
- https://blog.cheg.ai/sitemap.xml
- https://blog.cheg.ai/robots.txt
