# NovaCRM API

Referência oficial da **NovaCRM REST API v1** para integrações com clientes, catálogo, estoque, pedidos, cupons, loja, analytics, webhooks, importações e exportações.

| Recurso | Endereço |
|---|---|
| Documentação interativa | [console.novacrm.com.br/docs/api](https://console.novacrm.com.br/docs/api) |
| Especificação OpenAPI 3.1 | [console.novacrm.com.br/api/v1/openapi.json](https://console.novacrm.com.br/api/v1/openapi.json) |
| Base URL | `https://console.novacrm.com.br/api/v1` |

> **Status do contrato:** versão `v1`. Os exemplos desta página usam dados fictícios e devem ser substituídos pelos valores da sua conta.

## 1. Primeira chamada

A integração segue quatro passos: crie uma chave no Console, selecione somente os escopos necessários, armazene a chave em um segredo do seu servidor e envie-a no header `Authorization`.

```bash
curl "https://console.novacrm.com.br/api/v1/clients?limit=20" \\
  -H "Authorization: Bearer ncrm_live.SUA_CHAVE_COMPLETA"
```

O segredo completo da chave é exibido uma única vez no momento da criação. **Nunca** o inclua em código frontend, aplicativos móveis, logs, imagens ou repositórios públicos.

## 2. Ambientes e autenticação

A API possui dois ambientes lógicos. Chaves `ncrm_live` acessam os dados de produção; chaves `ncrm_test` acessam a área de sandbox da mesma conta.

```http
Authorization: Bearer ncrm_live.MERCHANT_ID.KEY_ID.SECRET
```

A chave é composta por quatro partes separadas por ponto: o ambiente, o identificador do lojista, o identificador da chave e o segredo. O servidor armazena somente o hash SHA-256 do segredo.

A única rota pública é `GET /openapi.json`. Todas as demais rotas exigem uma chave válida, ativa e compatível com o ambiente solicitado.

### Escopos

| Escopo | Permissão |
|---|---|
| `clients:read` | Consultar clientes |
| `clients:write` | Criar, atualizar, arquivar e importar clientes |
| `products:read` | Consultar produtos |
| `products:write` | Criar, atualizar, arquivar e importar produtos |
| `orders:read` | Consultar pedidos |
| `orders:write` | Criar, atualizar status e cancelar pedidos |
| `inventory:read` | Consultar estoque, alertas e movimentações |
| `inventory:write` | Registrar ajustes de estoque |
| `coupons:read` | Listar e validar cupons |
| `coupons:write` | Criar, atualizar e excluir cupons |
| `store:read` | Consultar configurações e status da loja |
| `store:write` | Alterar configurações, status e entrega |
| `analytics:read` | Consultar indicadores |
| `webhooks:read` | Listar webhooks e entregas |
| `webhooks:write` | Criar, atualizar, testar e excluir webhooks |
| `exports:read` | Baixar exportações |
| `exports:write` | Criar exportações |
| `dangerous:delete` | Excluir clientes ou produtos definitivamente |

## 3. Formato das respostas

Respostas JSON bem-sucedidas usam um envelope estável com `success`, `data` e `meta`.

```json
{
  "success": true,
  "data": {
    "clients": []
  },
  "meta": {
    "apiVersion": "v1",
    "requestId": "request-id",
    "timestamp": "2026-08-15T12:00:00.000Z",
    "resource": "clients"
  }
}
```

`requestId` identifica a requisição e deve ser preservado em logs de integração e chamados de suporte. Operações de criação, atualização e exclusão também podem incluir `operation` em `meta`.

## 4. Paginação e filtros

As rotas de listagem aceitam `limit` entre `1` e `100`, com padrão `50`, e `offset` a partir de `0`. A resposta inclui metadados para continuar a leitura sem duplicar páginas.

```bash
curl "https://console.novacrm.com.br/api/v1/products?limit=50&offset=100&includeArchived=false" \\
  -H "Authorization: Bearer ncrm_live.SUA_CHAVE_COMPLETA"
```

```json
{
  "meta": {
    "pagination": {
      "total": 128,
      "count": 28,
      "limit": 50,
      "offset": 100,
      "hasMore": false,
      "nextOffset": null
    }
  }
}
```

`includeArchived=true` inclui registros arquivados nas listagens de clientes e produtos. A listagem de pedidos aceita ainda `status` como filtro.

## 5. Referência de endpoints

Todas as rotas abaixo usam a [Base URL](#nova-crm-api). Os parâmetros `:id` representam o identificador do recurso.

### Clientes

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/clients` | `clients:read` | Lista clientes com paginação. |
| `POST` | `/clients` | `clients:write` | Cria um cliente. `name` é obrigatório. |
| `GET` | `/clients/:id` | `clients:read` | Consulta um cliente. |
| `PATCH` | `/clients/:id` | `clients:write` | Atualiza somente os campos enviados. |
| `DELETE` | `/clients/:id` | `clients:write` | Arquiva o cliente. |
| `DELETE` | `/clients/:id?permanent=true` | `dangerous:delete` | Exclui definitivamente o cliente. |
| `POST` | `/clients/upsert` | `clients:write` | Cria ou atualiza por telefone ou e-mail. |
| `POST` | `/imports/clients` | `clients:write` | Importa até 500 clientes. |

Exemplo de criação:

```json
{
  "name": "Maria Silva",
  "phone": "5512999999999",
  "email": "maria@exemplo.com",
  "status": "potential",
  "tags": ["vip"]
}
```

A resposta retorna o recurso em `data.client`. O serializador público normaliza os dados em `contact`, `address`, `stats`, `timestamps` e `metadata`.

### Produtos

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/products` | `products:read` | Lista produtos com paginação. |
| `POST` | `/products` | `products:write` | Cria um produto. `name` e `price` são obrigatórios. |
| `GET` | `/products/:id` | `products:read` | Consulta preço, estoque, mídia e opções. |
| `PATCH` | `/products/:id` | `products:write` | Atualiza somente os campos enviados. |
| `DELETE` | `/products/:id` | `products:write` | Arquiva o produto. |
| `DELETE` | `/products/:id?permanent=true` | `dangerous:delete` | Exclui definitivamente o produto. |
| `POST` | `/products/bulk` | `products:write` | Cria até 100 produtos. |
| `POST` | `/imports/products` | `products:write` | Importa até 500 produtos. |

```json
{
  "name": "Camiseta Premium",
  "price": 89.9,
  "stock": 25,
  "category": "Moda",
  "description": "Algodão premium"
}
```

### Estoque

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/inventory` | `inventory:read` | Lista o estoque atual. |
| `GET` | `/inventory/alerts?threshold=5` | `inventory:read` | Lista produtos no limite ou abaixo dele. |
| `GET` | `/inventory/movements` | `inventory:read` | Lista movimentações com paginação. |
| `POST` | `/inventory/adjustments` | `inventory:write` | Registra uma entrada ou saída. |

```json
{
  "productId": "prod123",
  "quantityDelta": -2,
  "reason": "venda externa",
  "lowStockThreshold": 5
}
```

`quantityDelta` deve ser diferente de zero. A API não permite estoque negativo: o valor atual é limitado a zero.

### Pedidos

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/orders` | `orders:read` | Lista pedidos; aceita o filtro `status`. |
| `POST` | `/orders` | `orders:write` | Cria pedido para um sistema externo. |
| `GET` | `/orders/:id` | `orders:read` | Consulta um pedido. |
| `PATCH` | `/orders/:id/status` | `orders:write` | Atualiza o status. |
| `POST` | `/orders/:id/cancel` | `orders:write` | Cancela o pedido e registra o motivo. |

Status aceitos: `pending_payment`, `new`, `processing`, `completed` e `cancelled`.

```json
{
  "customerName": "Maria Silva",
  "customerPhone": "5512999999999",
  "items": [
    {
      "productId": "prod123",
      "productName": "Camiseta Premium",
      "quantity": 2,
      "price": 89.9
    }
  ]
}
```

### Cupons

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/coupons` | `coupons:read` | Lista os cupons da loja. |
| `POST` | `/coupons` | `coupons:write` | Cria cupom percentual ou fixo. |
| `PATCH` | `/coupons/:id` | `coupons:write` | Atualiza código, tipo, valor, mínimo ou atividade. |
| `DELETE` | `/coupons/:id` | `coupons:write` | Exclui o cupom. |
| `POST` | `/coupons/validate` | `coupons:read` | Valida o código e calcula o desconto. |

```json
{
  "code": "PROMO10",
  "type": "percentage",
  "value": 10,
  "minPurchase": 50
}
```

`type` pode ser `percentage` ou `fixed`. A validação retorna `valid: false` com a razão `not_found` ou `minimum_purchase` quando o desconto não pode ser aplicado.

### Loja e entrega

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/store` | `store:read` | Consulta a configuração pública da loja. |
| `PATCH` | `/store` | `store:write` | Atualiza nome, descrição, categoria, mídia e horários. |
| `GET` | `/store/status` | `store:read` | Consulta abertura e publicação. |
| `PATCH` | `/store/status` | `store:write` | Atualiza `isOpen` e `isPublished`. |
| `GET` | `/store/delivery` | `store:read` | Consulta as configurações de entrega. |
| `PATCH` | `/store/delivery` | `store:write` | Atualiza as configurações de entrega. |

### Analytics

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/analytics` | `analytics:read` | Resumo financeiro, pedidos e recursos. |
| `GET` | `/analytics/revenue` | `analytics:read` | Receita, ticket médio e pedidos pagos. |
| `GET` | `/analytics/orders` | `analytics:read` | Pedidos agrupados por status. |
| `GET` | `/analytics/products` | `analytics:read` | Produtos mais vendidos e estoque baixo. |
| `GET` | `/analytics/clients` | `analytics:read` | LTV e clientes de maior valor. |
| `GET` | `/analytics/inventory` | `analytics:read` | Unidades, indisponibilidade e estoque baixo. |

### Webhooks

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `GET` | `/webhooks` | `webhooks:read` | Lista endpoints configurados. |
| `POST` | `/webhooks` | `webhooks:write` | Cria endpoint HTTPS e gera segredo de assinatura. |
| `PATCH` | `/webhooks/:id` | `webhooks:write` | Atualiza URL, eventos ou atividade. |
| `DELETE` | `/webhooks/:id` | `webhooks:write` | Exclui o webhook. |
| `GET` | `/webhooks/:id/deliveries` | `webhooks:read` | Lista o histórico de entregas. |
| `POST` | `/webhooks/:id/test` | `webhooks:write` | Enfileira um evento de teste. |

Eventos disponíveis:

`client.created`, `client.updated`, `client.deleted`, `product.created`, `product.updated`, `product.deleted`, `inventory.adjusted`, `inventory.low`, `order.created`, `order.status_updated`, `order.cancelled` e `*`.

O `signingSecret` é retornado somente na criação. Cada entrega contém um payload com `id`, `event`, `createdAt` e `data`, além dos headers abaixo:

```http
X-NovaCRM-Event: order.created
X-NovaCRM-Delivery: delivery-id
X-NovaCRM-Attempt: 1
X-NovaCRM-Signature: sha256=hex-signature
```

A assinatura é um HMAC-SHA256 calculado sobre o **corpo bruto** da requisição. Compare o valor recebido com uma comparação em tempo constante. A entrega tenta novamente até três vezes quando necessário.

### Importação e exportação

| Método | Rota | Escopo | Descrição |
|---|---|---|---|
| `POST` | `/imports/clients` | `clients:write` | Importa até 500 clientes no campo `records`. |
| `POST` | `/imports/products` | `products:write` | Importa até 500 produtos no campo `records`. |
| `POST` | `/exports` | `exports:write` | Prepara uma exportação `json` ou `csv`. |
| `GET` | `/exports/:id` | `exports:read` | Retorna JSON ou baixa CSV. |

Exportações ficam disponíveis por 24 horas. Para CSV, a resposta é um arquivo com `Content-Disposition: attachment`; para JSON, a resposta retorna os registros em `data.export.records`.

## 6. Tratamento de erros

Toda falha JSON segue o mesmo formato:

```json
{
  "success": false,
  "error": {
    "code": "validation_error",
    "message": "Existem campos inválidos na requisição.",
    "details": {
      "fields": [
        { "field": "phone", "message": "Informe um telefone válido." }
      ]
    }
  },
  "meta": {
    "apiVersion": "v1",
    "requestId": "request-id",
    "timestamp": "2026-08-15T12:00:00.000Z"
  }
}
```

| HTTP | Código | Quando ocorre |
|---:|---|---|
| `400` | `invalid_id` | Identificador com formato inválido. |
| `401` | `unauthorized` | Header `Authorization` ausente ou malformado. |
| `401` | `invalid_api_key` | Chave inexistente, revogada ou incompatível com o ambiente. |
| `403` | `account_unavailable` | Conta bloqueada ou indisponível. |
| `403` | `insufficient_scope` | A chave não possui o escopo da rota. |
| `404` | `route_not_found` | Método ou caminho não existe. |
| `404` | `*_not_found` | Recurso solicitado não foi encontrado. |
| `422` | `validation_error` | Corpo ou parâmetros inválidos. |
| `429` | `rate_limit_exceeded` | Limite por minuto atingido. |
| `429` | `monthly_limit_exceeded` | Limite mensal do plano atingido. |
| `500` | `internal_error` | Falha inesperada no processamento. |
| `503` | `service_unavailable` | Serviço não está configurado ou disponível. |

Em respostas `404` por rota inexistente, `error.details.documentation` pode apontar para a especificação OpenAPI.

## 7. Limites e observabilidade

| Plano | Requisições por mês | Requisições por minuto |
|---|---:|---:|
| Free | 100 | 10 |
| Pro | 10.000 | 60 |
| Enterprise | 100.000 | 300 |

Respostas autenticadas incluem `X-Request-Id`, `X-RateLimit-Limit` e `X-RateLimit-Remaining`. Ao atingir o limite por minuto, a API retorna HTTP `429` e o header `Retry-After`, em segundos.

Use backoff exponencial para novas tentativas. Não repita automaticamente operações de criação sem uma estratégia de idempotência no sistema de origem.

## 8. OpenAPI e compatibilidade

A especificação disponível em [`/openapi.json`](https://console.novacrm.com.br/api/v1/openapi.json) usa OpenAPI `3.1.0` e pode ser importada no Postman, Insomnia, Swagger UI e geradores de SDK. Ela descreve a base da API, os esquemas de autenticação e todas as rotas públicas do contrato.

Antes de atualizar uma integração, consulte a especificação e preserve o tratamento de `requestId`, códigos HTTP e envelopes de resposta. Alterações incompatíveis serão associadas a uma nova versão da API.

## 9. Exemplos por linguagem

### Node.js

```js
const baseUrl = 'https://console.novacrm.com.br/api/v1';

const response = await fetch(`${baseUrl}/clients?limit=50`, {
  headers: {
    Authorization: `Bearer ${process.env.NOVACRM_API_KEY}`,
  },
});

const result = await response.json();
console.log(result.data.clients);
```

### Python

```python
import os
import requests

response = requests.get(
    "https://console.novacrm.com.br/api/v1/products",
    headers={"Authorization": f"Bearer {os.environ['NOVACRM_API_KEY']}"},
    params={"limit": 50},
)

response.raise_for_status()
print(response.json()["data"]["products"])
```

### cURL com JSON

```bash
curl -X POST "https://console.novacrm.com.br/api/v1/orders" \\
  -H "Authorization: Bearer ncrm_live.SUA_CHAVE_COMPLETA" \\
  -H "Content-Type: application/json" \\
  -d '{
    "customerName": "Maria Silva",
    "items": [{"productId": "prod123", "quantity": 1, "price": 89.90}]
  }'
```

## 10. Checklist de produção

Antes de liberar a integração, confirme que a chave está em um gerenciador de segredos, que o ambiente usado é o correto, que os escopos estão limitados ao necessário e que os logs preservam `X-Request-Id` sem registrar o segredo da chave. Também valide assinaturas de webhook antes de processar o evento e implemente tratamento para `401`, `403`, `404`, `422` e `429`.

Para uma experiência interativa, use a [documentação pública](https://console.novacrm.com.br/docs/api). Para gerar clientes ou importar o contrato em uma ferramenta, use a [especificação OpenAPI](https://console.novacrm.com.br/api/v1/openapi.json).

---

**NovaCRM Developers** · API REST v1
