Garu

2026-05-17

v0.10.0 — Configuração de portal por produto aceita UUID

portalprodutosapib2b2c

Quem integra Garu via API normalmente recebe UUIDs (list_products, webhooks, GET /api/products). Mas os endpoints /portal-config exigiam o id numérico interno — uma pegadinha que custou um incidente real (UUID era convertido pra 0 ou NaN por parseInt, e devolvia 500 em vez de uma mensagem útil).

A v0.10.0 corrige os dois lados: aceita UUID no endpoint canônico e devolve 400 limpo quando a entrada não é nem UUID nem id numérico.

O que mudou

GET/POST/PATCH/DELETE /api/products/:id/portal-config aceita UUID

:id agora aceita o UUID do produto (preferido) ou o id numérico legado. A resolução é automática — strings numéricas vão pelo path inteiro, qualquer outra string é tratada como UUID.

# UUID — recomendado
curl -X POST https://garu.com.br/api/products/a1b2c3d4-e5f6-7890-abcd-ef1234567890/portal-config \
  -H "Authorization: Bearer $GARU_API_KEY" \
  -d '{"businessName": "Coach Maria", "primaryColor": "#257264"}'

# Id numérico — ainda funciona (back-compat)
curl -X POST https://garu.com.br/api/products/57/portal-config \
  -H "Authorization: Bearer $GARU_API_KEY" \
  -d '{"businessName": "Coach Maria", "primaryColor": "#257264"}'

A ownership check carrega o produto pelo identificador resolvido e valida que pertence ao seller chamando — mesma garantia de antes, agora com mais de um identificador na porta de entrada.

Endpoint legado /api/portal/configuration/product/:id devolve 400 em vez de 500

GET e PUT /api/portal/configuration/product/:productId continuam aceitando só o id numérico (esse endpoint está deprecado em favor do canônico acima). Mas agora ParseIntPipe rejeita entradas não-numéricas com 400 "Validation failed (numeric string is expected)" antes de tocar o banco — antes, parseInt silencioso convertia "abc…" em NaN e a query falhava com 500 genérico.

Entradas inválidas no endpoint canônico devolvem 404 (não 500)

Strings que não são nem UUID válido nem id inteiro (ex.: "abc", UUID truncado) eram passadas direto pro Postgres, que respondia invalid input syntax for type uuid → 500 genérico — exatamente a mesma classe de bug que motivou a versão. Agora a validação acontece no service (isUUID do class-validator) antes da query e devolve 404.

Comportamento de ownership: 404 em vez de 403

Quando o caller passa um identificador (UUID ou id) de um produto que existe mas pertence a outro seller, a resposta agora é 404 Product not found em vez de 403 Product does not belong to this seller. Pequena mudança de contrato, motivada por segurança: a resposta 403 confirmava a existência do recurso pra quem não deveria saber. Comportamento "exists but not yours" e "doesn't exist" agora são indistinguíveis.

Doc consolidada

A seção "Configuração por Produto" em /api-reference/assinaturas/portal virou um link pra página canônica em /api-reference/produtos/portal-config. Sem mais dois exemplos divergentes pra mesma feature.

Migração

Aditivo, sem breaking change. Quem chama com id numérico continua igual. Quem quiser migrar pra UUID pode trocar o segmento do path — não precisa mudar mais nada.

SDK e MCP

@garuhq/node e @garuhq/mcp ainda assinam productId: number. A REST API aceita UUID hoje; o wrapper UUID-first no SDK e a atualização da descrição da MCP tool vêm num release próximo.