# API Pública Nova — Referência para LLMs

Resumo compacto e legível por máquina da API de desenvolvedores da Nova. A
versão humana fica em <https://novadao.app/pt/devs>. As duas são geradas a partir
do mesmo spec em TypeScript, então ficam sempre em sincronia.

- URL base: `https://novadao.app`
- Prefixo versionado: `/api/v1/`
- Todas as requisições e respostas são JSON.
- Envie a chave de API como `Authorization: Bearer <chave>`. Nunca `X-Api-Key`.
- Apenas servidor-a-servidor por padrão. Chamadas do navegador (requisições com cabeçalho `Origin`) são bloqueadas a não ser que o usuário tenha cadastrado a origem em allowed_domains da chave.

## Contrato de produção da API

A v1 da Nova é pequena de propósito:

- Um caminho base: toda rota autenticada fica em `/api/v1`.
- Um tipo de auth: `Authorization: Bearer <chave>`.
- Uma superfície de SDK: SDKs públicos chamam apenas `/api/v1/*`. `/api/wallet/*` é da SPA Nova logada e usa cookies com CSRF.
- Respostas com sucesso devolvem o recurso direto; erros sempre usam `{ "error": ... }`.
- POSTs que mexem com dinheiro exigem `Idempotency-Key`; `X-Idempotency-Key` também é aceito.
- Recebedores de webhook devem verificar `Nova-Signature` contra o corpo bruto.
- Regra de quebra mínima: a v1 mantém nomes e sentidos atuais; adições são aditivas.

## Pacote SDK

O pacote TypeScript `@novadao/sdk` é fino: um transporte HTTP, grupos tipados por recurso, erros tipados, idempotência como opção explícita e verificação de webhook incluída. Ele não esconde retries de POST se o chamador não enviou uma chave de idempotência.

Instale:

```bash
npm install @novadao/sdk
```

Página do pacote: <https://www.npmjs.com/package/@novadao/sdk>

```ts
type NovaApiError = {
  status: number;
  code: string;
  message: string;
  requestId: string;
};

type PixCharge = {
  id: string;
  status: 'pending' | 'paid' | 'expired' | 'failed';
  amountInCents: number | null;
  qrCopyPaste: string | null;
  qrImageUrl: string | null;
  blockchainTxId: string | null;
  createdAt: string;
};

type PaymentLink = {
  id: string;
  name: string;
  mode: 'fixed' | 'range' | 'open';
  status: 'active' | 'paused';
  url: string;
  handle: string;
  slug: string;
  amountBrl: number | null;
  minBrl: number | null;
  maxBrl: number | null;
  depixAddress: string;
  createdAt: string;
};

type WebhookEndpoint = {
  id: number;
  url: string;
  events: string[];
  status: 'active' | 'disabled';
  createdAt: string;
};

type CreatedWebhookEndpoint = WebhookEndpoint & {
  signingSecret: string;
};

type NovaClient = {
  pix: {
    createCharge(
      input: { amountInCents: number; depixAddress: string },
      options: { idempotencyKey: string },
    ): Promise<PixCharge>;
    getCharge(id: string): Promise<PixCharge>;
  };
  paymentLinks: {
    create(input: CreatePaymentLink, options?: { idempotencyKey?: string }): Promise<PaymentLink>;
    get(id: string): Promise<PaymentLink>;
    pause(id: string): Promise<PaymentLink>;
  };
  webhooks: {
    list(): Promise<WebhookEndpoint[]>;
    create(
      input: CreateWebhookEndpoint,
      options: { idempotencyKey: string },
    ): Promise<CreatedWebhookEndpoint>;
    remove(id: number): Promise<{ id: number; deleted: true }>;
    test(id: number): Promise<{ deliveryId: string; queuedAt: string }>;
    verifySignature(
      rawBody: string | Uint8Array,
      header: string,
      secret: string,
      options?: { toleranceSeconds?: number },
    ): Promise<boolean>;
  };
};
```

Uso recomendado:

```ts
import { NovaClient, createIdempotencyKey } from '@novadao/sdk';

const nova = new NovaClient({
  apiKey: process.env.NOVA_API_KEY!,
});

const charge = await nova.pix.createCharge(
  { amountInCents: 100, depixAddress: 'lq1...' },
  { idempotencyKey: createIdempotencyKey('pix') },
);
```

Regras de implementação:

- Lance `NovaApiError` com `status`, `code`, `message` e `requestId` para envelopes de erro.
- Tipifique falhas usando `status` e `code`; o mesmo código pode aparecer com status HTTP diferente.
- Repita apenas erros de rede, `408`, `429` e `5xx`. Respeite `Retry-After`.
- Nunca repita `POST /pix/charges` sem chave de idempotência. Para a mesma requisição lógica, repita com a mesma chave; use chave nova apenas para uma cobrança nova.
- Exija chave de idempotência em `webhooks.create` no SDK, mesmo que a API crua aceite como opcional.
- Aceite snake_case da API, mas exponha tipos camelCase em TypeScript.

## Autenticação

```
Authorization: Bearer nv_live_8aXk3rT9...
```

O usuário cria uma chave de API no aplicativo Nova (Conta → Desenvolvedor)
depois que sua conta é aprovada pela equipe ops. A aprovação é única por
conta; depois disso o usuário pode criar e revogar chaves livremente.

## Limites de taxa (por chave)

- Tier 1 (padrão): 60 req/min, 10.000 req/dia. Sublimite POST /pix/charges: 30/min.
- Tier 2 (sob demanda): 600 req/min, 200.000 req/dia. Sublimite POST /pix/charges: 300/min.

Toda resposta autenticada traz:
```
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
X-RateLimit-Daily-Limit, X-RateLimit-Daily-Remaining, X-RateLimit-Daily-Reset
```

Respostas 429 incluem `Retry-After` (em segundos).

## Idempotência

Envie um cabeçalho `Idempotency-Key` único (1..255 caracteres ASCII) em
POSTs que criam estado real. `X-Idempotency-Key` também é aceito. Obrigatória
em `POST /api/v1/pix/charges`; opcional em payment-links e webhooks. Respostas
cacheadas vivem 24h. Respostas 5xx não são cacheadas.

- Replay (mesma chave, mesmo corpo): resposta cacheada com `X-Idempotent-Replay: true`.
- Em processamento (mesma chave ainda rodando): `409 idempotency_key_in_progress`.
- Conflito (mesma chave, corpo diferente): `409 idempotency_key_reused`.

## Envelope de erro

Todos os erros compartilham este formato. O `request_id` é único e é o único identificador que você precisa enviar para o suporte da Nova.

```json
{
  "error": {
    "code": "<error_code>",
    "message": "Human-readable explanation.",
    "request_id": "req_...",
    "docs_url": "https://novadao.app/pt/devs/errors#<error_code>"
  }
}
```

| HTTP | código | significado |
|------|--------|-------------|
| 401 | `auth_missing` | Nenhum cabeçalho Authorization foi enviado. |
| 401 | `auth_use_bearer` | Você enviou X-Api-Key. Use Authorization: Bearer <chave> no lugar. |
| 401 | `auth_invalid` | A chave de API é inválida, revogada ou não aprovada. |
| 403 | `browser_origin_disallowed` | Requisição do navegador cujo Origin não está em allowed_domains da chave. Chamadas servidor-a-servidor não devem enviar Origin. |
| 403 | `ip_not_allowlisted` | O IP da requisição não está na lista de IPs permitidos da conta. |
| 429 | `rate_limited` | Muitas requisições. Leia X-RateLimit-Reset e Retry-After. O esgotamento do limite diário usa o mesmo código. |
| 400 / 409 / 422 | `invalid_payload` | O corpo, caminho ou operação falhou na validação. SDKs devem guardar o status HTTP e o error.code. |
| 400 | `invalid_json` | O corpo da requisição está vazio ou não é um JSON válido. |
| 413 | `payload_too_large` | O corpo da requisição é maior do que o endpoint aceita. |
| 400 | `idempotency_key_required` | POST /pix/charges exige Idempotency-Key em toda requisição. |
| 409 | `idempotency_key_in_progress` | Uma requisição com esta Idempotency-Key ainda está processando. Repita a mesma requisição em instantes. |
| 409 | `idempotency_key_reused` | Você enviou a mesma Idempotency-Key com um corpo diferente. Gere uma nova chave para novas requisições. |
| 404 | `not_found` | O recurso não existe ou não é seu. |
| 503 | `payment_service_unavailable` | O provedor de pagamento está temporariamente indisponível. Repita a mesma requisição lógica com a mesma Idempotency-Key. |
| 500 | `internal_error` | Algo deu errado do nosso lado. |

## Endpoints

### GET /api/v1/health

Verificação de vida (liveness).

Auth: nenhuma.

Sem autenticação, sem limite de taxa, sem banco. Retorna 200 enquanto a API estiver rodando. Use em páginas de status e monitores de uptime.

Formato da resposta:
```json
{ "ok": true, "service": "nova-public-api", "server_time": "ISO8601" }
```

Exemplo — Conferir se a API está no ar:
```bash
curl https://novadao.app/api/v1/health
```
Retorna:
```json
{
  "ok": true,
  "service": "nova-public-api",
  "server_time": "2026-04-25T12:34:56.000Z"
}
```

### GET /api/v1/ping

Round-trip autenticado.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Confirma que sua chave de API funciona e mostra o que o servidor vê: o id da chave, o tier, os domínios permitidos e o horário do servidor. O botão "testar conexão" do painel chama este endpoint.

Parâmetros:
- `Authorization` (header, string, obrigatório) — Bearer <sua-chave-de-api>

Formato da resposta:
```json
{ "ok": true, "key_id": number, "tier": "tier1" | "tier2", "allowed_domains": string[], "server_time": "ISO8601", "request_id": "req_..." }
```

Exemplo — Validar sua chave:
```bash
curl -H "Authorization: Bearer $NOVA_API_KEY" \
  https://novadao.app/api/v1/ping
```
Retorna:
```json
{
  "ok": true,
  "key_id": 42,
  "tier": "tier1",
  "allowed_domains": [],
  "server_time": "2026-04-25T12:34:56.000Z",
  "request_id": "req_8aXk..."
}
```

### POST /api/v1/pix/charges

Criar uma cobrança PIX (QR code).

Auth: Bearer (chave de API obrigatória, conta aprovada).
Idempotência: `Idempotency-Key` required.
Limite de taxa: tier1: 30/min · tier2: 300/min.

Gera um QR code PIX que o seu cliente pode pagar. Preste atenção a dois cabeçalhos: Authorization e Idempotency-Key. A Idempotency-Key é OBRIGATÓRIA — ela permite repetir uma chamada após erro de rede sem cobrar duas vezes.

Parâmetros:
- `Authorization` (header, string, obrigatório) — Bearer <sua-chave-de-api>
- `Idempotency-Key` (header, string, obrigatório) — Um valor único que você gera por requisição (1..255 caracteres ASCII). `X-Idempotency-Key` também é aceito.
- `amount_in_cents` (body, integer, obrigatório) — Valor da cobrança em centavos (BRL). Mínimo 100 (R$ 1,00).
- `depix_address` (body, string, obrigatório) — Endereço confidencial da rede Liquid (`lq1...`) que vai receber os DePix quando a cobrança liquidar.

Formato da resposta:
```json
{ "id": "...", "status": "pending", "amount_in_cents": number, "qr_copy_paste": "...", "qr_image_url": "...", "blockchain_tx_id": null, "created_at": "ISO8601" }
```

Exemplo — Criar uma cobrança de R$ 50:
```bash
curl -X POST https://novadao.app/api/v1/pix/charges \
  -H "Authorization: Bearer $NOVA_API_KEY" \
  -H "Idempotency-Key: order-1234" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_in_cents": 5000,
    "depix_address": "lq1..."
  }'
```
Retorna:
```json
{
  "id": "ch_a8b3...",
  "status": "pending",
  "amount_in_cents": 5000,
  "qr_copy_paste": "00020126580014BR.GOV.BCB.PIX...",
  "qr_image_url": "https://novadao.app/api/v1/pix/charges/ch_a8b3.../qr.png",
  "blockchain_tx_id": null,
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### GET /api/v1/pix/charges/:id

Consultar uma cobrança PIX.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Retorna o status atual de uma cobrança PIX. Assine `pix.charge.received` quando precisar da confirmação bancária do pagamento, e `pix.charge.paid` quando precisar da transação liquidada na Liquid.

Parâmetros:
- `id` (path, string, obrigatório) — O id da cobrança retornado por POST /pix/charges.

Formato da resposta:
```json
{ "id": "...", "status": "pending" | "paid" | "expired" | "failed", "amount_in_cents": number, "qr_copy_paste": "...", "qr_image_url": "...", "blockchain_tx_id": "..." | null, "created_at": "ISO8601" }
```

Exemplo — Conferir se a cobrança foi paga:
```bash
curl -H "Authorization: Bearer $NOVA_API_KEY" \
  https://novadao.app/api/v1/pix/charges/ch_a8b3
```
Retorna:
```json
{
  "id": "ch_a8b3...",
  "status": "paid",
  "amount_in_cents": 5000,
  "qr_copy_paste": "00020126580014BR.GOV.BCB.PIX...",
  "qr_image_url": "https://novadao.app/api/v1/pix/charges/ch_a8b3.../qr.png",
  "blockchain_tx_id": "7f4a...",
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### POST /api/v1/payment-links

Criar um link de pagamento reutilizável.

Auth: Bearer (chave de API obrigatória, conta aprovada).
Idempotência: `Idempotency-Key` optional.
Limite de taxa: tier1: 60/min.

Gera uma URL pública de checkout (`https://novadao.app/c/<handle>/<slug>`) que aceita pagamentos. Três modos: `fixed` (valor único), `range` (mín/máx), `open` (qualquer valor, com limites opcionais).

Parâmetros:
- `name` (body, string, obrigatório) — 1 a 80 caracteres. Usado para gerar o slug.
- `mode` (body, "fixed" | "range" | "open", obrigatório) — Modelo de preço.
- `amount_brl` (body, number) — Obrigatório quando mode é "fixed".
- `min_brl` (body, number) — Usado quando mode é "range" (obrigatório) ou "open" (opcional).
- `max_brl` (body, number) — Usado quando mode é "range" (obrigatório) ou "open" (opcional).
- `depix_address` (body, string, obrigatório) — Endereço confidencial da rede Liquid (`lq1...`) que recebe DePix a cada pagamento bem-sucedido.
- `options` (body, object) — Opcional: { ask_name?: bool, ask_email?: bool, thank_you_message?: string, sales_limit?: int }.

Formato da resposta:
```json
{ "id": "lk_...", "name": "...", "mode": "fixed" | "range" | "open", "status": "active", "url": "https://...", "handle": "...", "slug": "...", "amount_brl": number | null, "min_brl": number | null, "max_brl": number | null, "depix_address": "...", "created_at": "ISO8601" }
```

Exemplo — Vender uma pizza por R$ 25:
```bash
curl -X POST https://novadao.app/api/v1/payment-links \
  -H "Authorization: Bearer $NOVA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pizza margherita",
    "mode": "fixed",
    "amount_brl": 25,
    "depix_address": "lq1..."
  }'
```
Retorna:
```json
{
  "id": "lk_HQKFuN22r39cc1Dp",
  "name": "Pizza margherita",
  "mode": "fixed",
  "status": "active",
  "url": "https://novadao.app/c/myshop/pizza-margherita",
  "handle": "myshop",
  "slug": "pizza-margherita",
  "amount_brl": 25,
  "min_brl": null,
  "max_brl": null,
  "depix_address": "lq1...",
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### GET /api/v1/payment-links/:id

Consultar um link de pagamento.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Retorna o estado atual de um link de pagamento, incluindo a URL pública.

Parâmetros:
- `id` (path, string, obrigatório) — O id do link.

Formato da resposta:
```json
{ "id": "lk_...", ... same shape as POST response, but "status" can also be "paused" }
```

Exemplo — Consultar um link antes de exibir:
```bash
curl -H "Authorization: Bearer $NOVA_API_KEY" \
  https://novadao.app/api/v1/payment-links/lk_HQKFuN22r39cc1Dp
```
Retorna:
```json
{
  "id": "lk_HQKFuN22r39cc1Dp",
  "name": "Pizza margherita",
  "mode": "fixed",
  "status": "active",
  "url": "https://novadao.app/c/myshop/pizza-margherita",
  "handle": "myshop",
  "slug": "pizza-margherita",
  "amount_brl": 25,
  "min_brl": null,
  "max_brl": null,
  "depix_address": "lq1...",
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### DELETE /api/v1/payment-links/:id

Pausar um link de pagamento.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Exclusão branda: pausa o link para que ele pare de aceitar pagamentos novos. URLs já distribuídas mostram uma página "pausado" em vez de 404, evitando que clientes em checkout vejam um erro confuso.

Parâmetros:
- `id` (path, string, obrigatório) — O id do link.

Formato da resposta:
```json
{ "id": "lk_...", "name": "...", "mode": "fixed" | "range" | "open", "status": "paused", "url": "https://...", "handle": "...", "slug": "...", "amount_brl": number | null, "min_brl": number | null, "max_brl": number | null, "depix_address": "...", "created_at": "ISO8601" }
```

Exemplo — Pausar um link:
```bash
curl -X DELETE https://novadao.app/api/v1/payment-links/lk_HQKFuN22r39cc1Dp \
  -H "Authorization: Bearer $NOVA_API_KEY"
```
Retorna:
```json
{
  "id": "lk_HQKFuN22r39cc1Dp",
  "name": "Pizza margherita",
  "mode": "fixed",
  "status": "paused",
  "url": "https://novadao.app/c/myshop/pizza-margherita",
  "handle": "myshop",
  "slug": "pizza-margherita",
  "amount_brl": 25,
  "min_brl": null,
  "max_brl": null,
  "depix_address": "lq1...",
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### GET /api/v1/webhooks

Listar webhooks.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Retorna todos os webhooks da sua conta.

Formato da resposta:
```json
{ "webhooks": [{ "id": number, "url": "...", "events": string[], "status": "active" | "disabled", "created_at": "ISO8601" }] }
```

Exemplo — Listar webhooks configurados:
```bash
curl -H "Authorization: Bearer $NOVA_API_KEY" \
  https://novadao.app/api/v1/webhooks
```
Retorna:
```json
{
  "webhooks": [
    {
      "id": 7,
      "url": "https://yourshop.com/webhooks/nova",
      "events": ["pix.charge.paid", "payment_link.paid"],
      "status": "active",
      "created_at": "2026-04-25T12:34:56.000Z"
    }
  ]
}
```

### POST /api/v1/webhooks

Assinar eventos.

Auth: Bearer (chave de API obrigatória, conta aprovada).
Idempotência: `Idempotency-Key` optional.

Cria um inscrito de webhook. A resposta inclui um `signing_secret` mostrado uma única vez — guarde com cuidado; você vai precisar dele para verificar a assinatura de cada entrega.

Parâmetros:
- `url` (body, string (URL), obrigatório) — Endpoint HTTPS que vai receber as entregas via POST.
- `events` (body, string[], obrigatório) — Um ou mais entre: pix.charge.created, pix.charge.received, pix.charge.paid, pix.charge.expired, pix.charge.failed, payment_link.paid.

Formato da resposta:
```json
{ "id": number, "url": "...", "events": string[], "status": "active", "signing_secret": "<base64url, shown once>", "created_at": "ISO8601" }
```

Exemplo — Assinar cobranças pagas:
```bash
curl -X POST https://novadao.app/api/v1/webhooks \
  -H "Authorization: Bearer $NOVA_API_KEY" \
  -H "Idempotency-Key: webhook-paid-events-v1" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourshop.com/webhooks/nova",
    "events": ["pix.charge.paid", "payment_link.paid"]
  }'
```
Retorna:
```json
{
  "id": 7,
  "url": "https://yourshop.com/webhooks/nova",
  "events": ["pix.charge.paid", "payment_link.paid"],
  "status": "active",
  "signing_secret": "Rll0hXsdn2hzp1G6...",
  "created_at": "2026-04-25T12:34:56.000Z"
}
```

### DELETE /api/v1/webhooks/:id

Cancelar a assinatura.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Remove um inscrito de webhook. Entregas já enfileiradas ainda são tentadas.

Parâmetros:
- `id` (path, integer, obrigatório) — Id do webhook.

Formato da resposta:
```json
{ "id": number, "deleted": true }
```

Exemplo — Remover um webhook:
```bash
curl -X DELETE https://novadao.app/api/v1/webhooks/7 \
  -H "Authorization: Bearer $NOVA_API_KEY"
```
Retorna:
```json
{
  "id": 7,
  "deleted": true
}
```

### POST /api/v1/webhooks/:id/test

Disparar uma entrega de teste.

Auth: Bearer (chave de API obrigatória, conta aprovada).

Enfileira uma entrega `webhook.test.ping` para a URL do seu webhook. Use para conferir que seu endpoint recebe e verifica assinaturas corretamente. A entrega é assinada igual a um evento real.

Parâmetros:
- `id` (path, integer, obrigatório) — Id do webhook.

Formato da resposta:
```json
{ "delivery_id": "whd_...", "queued_at": "ISO8601" }
```

Exemplo — Enviar um evento assinado de teste:
```bash
curl -X POST https://novadao.app/api/v1/webhooks/7/test \
  -H "Authorization: Bearer $NOVA_API_KEY"
```
Retorna:
```json
{
  "delivery_id": "whd_abc123",
  "queued_at": "2026-04-25T12:34:56.000Z"
}
```

## Webhooks

O usuário cria inscritos de webhook em `POST /api/v1/webhooks`. A Nova publica JSON na URL cadastrada sempre que um evento assinado é disparado.

### Nomes de evento e payloads

- `pix.charge.created` — Uma cobrança PIX acabou de ser criada. Útil para registrar a criação no seu banco de dados.
- `pix.charge.received` — Um cliente pagou a cobrança PIX no trilho bancário. Cobranças D+2 podem chegar com `status: "delayed"`, `settlement_status: "delayed"`, `delay_until`, `confirmed_at` e `blockchain_tx_id: null`, e liquidar depois via `pix.charge.paid`.
- `pix.charge.paid` — A cobrança PIX liquidou na Liquid e inclui o id da transação de liquidação.
- `pix.charge.expired` — Uma cobrança PIX expirou antes de ser paga.
- `pix.charge.failed` — Uma cobrança PIX falhou (cancelada, estornada ou rejeitada pela rede). Continue ouvindo este evento mesmo depois de `pix.charge.received`.
- `payment_link.paid` — Um checkout de link de pagamento foi concluído. Dispara junto com `pix.charge.paid` quando a cobrança veio de um link.

Todo payload é envelopado:

```json
{
  "api_version": "2026-04-24",
  "event": "<event_name>",
  "created_at": "ISO8601",
  "data": { ... event-specific fields ... }
}
```

### Cabeçalhos de entrega

```
Nova-Signature: t=<unix_seconds>,v1=<sha256_hmac_hex>
Nova-Event: <event_name>
Nova-Delivery-Id: whd_...
Nova-Api-Version: 2026-04-24
Content-Type: application/json; charset=utf-8
```

### Verificação da assinatura

`v1` é `HMAC-SHA256(signing_secret, t + "." + raw_body)`. O
`signing_secret` é retornado uma única vez na criação do webhook. Rejeite
assinaturas cujo `t` esteja a mais de 5 minutos do relógio do seu servidor.
Use os bytes brutos da requisição — nunca reserialize.

### Política de retry

Timeout de 15 segundos. 2xx é sucesso. Qualquer outra resposta enfileira
uma re-tentativa. O cronograma é 1m → 5m → 30m → 2h → 6h → 24h (seis
tentativas, contando a primeira). Após a última tentativa, a entrega é
marcada como `failed` e o dono da conta é avisado na sua caixa.

## Versionamento

`/api/v1/` é um contrato permanente. Novos campos e tipos de evento são
aditivos. Mudanças que quebram aparecem em `/api/v2/` com pelo menos 12
meses de sobreposição; respostas da v1 carregam `Deprecation: true` e
`Sunset: <RFC 9745>` durante o sunset. Payloads de webhook incluem
`api_version` para que assinantes possam ramificar.

## Bug bounty e divulgação responsável

Relatos privados vão para `hello@novadao.app` com o assunto `[security] <descrição curta>`. Não abra issues públicas nem divulgue detalhes até a Nova confirmar que a divulgação está liberada.

Escopo: superfícies de produção do produto e da API Nova sob `https://novadao.app`, incluindo `/app`, `/api/v1/*`, fluxos de conta/autenticação, links de pagamento, assinatura e entrega de webhooks, e problemas do site ou da documentação com impacto de segurança. Teste apenas em contas, chaves, webhooks, links de pagamento e dados que sejam seus ou que você tenha autorização explícita para testar.

Regras: inclua impacto, URL ou endpoint afetado, passos de reprodução e detalhes de prova de conceito. Mantenha os testes no mínimo necessário. Não acesse, modifique, apague nem extraia dados de outros usuários. Se dados sensíveis aparecerem, pare o teste e reporte imediatamente. Pesquisa de boa-fé que segue estas regras está coberta por safe harbor.

Fora de escopo: denial-of-service, teste de carga, brute force automatizado, engenharia social, phishing, ataques físicos, spam, provedores terceirizados, sistemas de parceiros, extensões de navegador, dispositivos de usuários, ambientes que não sejam produção salvo autorização explícita, duplicatas conhecidas, saída de scanner sem impacto demonstrado, problemas teóricos sem prova de conceito prática e problemas que afetam apenas navegadores desatualizados.

Recompensas: relatos validados podem ser elegíveis a recompensas discricionárias com base em severidade, impacto real, reprodutibilidade, explorabilidade, qualidade do relato e se o problema já era conhecido.

## Suporte

- Telegram: <https://t.me/novadao_supportbot>
- Inclua o `request_id` do envelope de erro em qualquer chamado.
- Documentação humana: <https://novadao.app/pt/devs>
