# Mudar o status da cotação

> Escopo: cotacoes:status (quem criou a chave precisa de cotacoes.enviar, como na tela). Não envia nada ao cliente e não mexe no link. Transições permitidas…

URL: https://precificador3d.com.br/docs/api/referencia/mudar-status-cotacao

`POST https://api.precificador3d.com.br/v1/cotacoes/{id}/status`

Escopo: `cotacoes:status` (quem criou a chave precisa de `cotacoes.enviar`, como na tela). Não envia nada ao cliente e não mexe no link.

**Transições permitidas pela API:** `rascunho` → `em_analise`, `aprovada`, `recusada` ou `arquivado`; `em_analise` e `enviada` → `aprovada`, `recusada` ou `arquivado`; `aprovada` e `recusada` → `arquivado`. Para `enviada`, para `rascunho` e entre `aprovada` e `recusada`, só pela tela. Fora disso: `422 transicao_invalida`.

`de` é obrigatório: se o status atual for outro, a resposta é `409 status_mudou` e nada muda.

Sair de `rascunho` ou `em_analise` **congela** a cotação (os valores não mudam mais e os itens deixam de ser editáveis), igual à tela. Aprovar não cria pedido de produção. Gera o webhook `cotacao.status_mudou` (e `cotacao.aprovada` ou `cotacao.recusada`) com `origem.chave_id` desta chave, para o integrador ignorar o eco. Escrita com custo 2.

Escopo: `cotacoes:status`.

## Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | path | string (uuid) | sim |  |
| `Idempotency-Key` | header | string | sim | Chave única da operação, guardada por 24 h junto com o hash do corpo, o status e o id
criado (sem corpo nem resposta). Repetir com o mesmo corpo devolve o mesmo status e o
recurso relido pelo id. A mesma chave com outro corpo responde `422 idempotencia_conflito`.
 (até 64 caracteres) |

## Corpo (application/json)

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `de` | string | sim | Valores: `rascunho`, `enviada`, `aprovada`, `recusada`, `em_analise`, `arquivado`. |
| `para` | string | sim | Valores: `em_analise`, `aprovada`, `recusada`, `arquivado`. |
| `motivo` | string | não | (até 200 caracteres) |

```json
{
  "de": "enviada",
  "para": "aprovada",
  "motivo": "Cliente aprovou por e-mail"
}
```

## Resposta 200

Status mudado. Devolve a cotação com o status novo.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | string (uuid) | sim |  |
| `codigo` | string | sim |  |
| `titulo` | string | sim |  |
| `status` | string | sim | Valores: `rascunho`, `enviada`, `aprovada`, `recusada`, `em_analise`, `arquivado`. |
| `versao` | integer | sim |  |
| `cliente` | object | sim |  |
| `cliente.nome` | string \| null | sim |  |
| `cliente.contato` | string \| null | sim |  |
| `validade` | string (date) \| null | sim |  |
| `condicoes` | string \| null | não |  |
| `observacao` | string \| null | não |  |
| `itens` | array de object | sim |  |
| `itens[].id` | string (uuid) | sim |  |
| `itens[].nome` | string | sim |  |
| `itens[].sku` | string \| null | sim |  |
| `itens[].produto_id` | string (uuid) \| null | sim |  |
| `itens[].variacao_id` | string (uuid) \| null | sim |  |
| `itens[].quantidade` | integer | sim |  |
| `itens[].preco_unitario_centavos` | integer | sim | (de 0 a 100000000000) |
| `itens[].total_centavos` | integer | sim | (de 0 a 100000000000) |
| `itens[].cor` | CorCliente \| null | sim |  |
| `itens[].cor.id` | string (uuid) | sim |  |
| `itens[].cor.codigo` | string | sim |  |
| `itens[].cor.nome_cliente` | string | sim |  |
| `itens[].cor.acabamento` | string | não | Valores: `nenhum`, `brilhante`, `fosco`. |
| `itens[].cor_a_combinar` | boolean | sim |  |
| `total_centavos` | integer | sim | (de 0 a 100000000000) |
| `desconto_centavos` | integer | sim | (de 0 a 100000000000) |
| `criado_em` | string (date-time) | sim |  |
| `atualizado_em` | string (date-time) | sim |  |
| `enviada_em` | string (date-time) \| null | não |  |
| `aprovada_em` | string (date-time) \| null | não |  |
| `congelada` | boolean | não | true fora de rascunho e em_analise. Congelada, a cotação só se edita voltando para rascunho pela tela. |
| `custo_total_centavos` | integer | não | [custos] (de 0 a 100000000000) |
| `lucro_centavos` | integer | não | [custos] |
| `margem_bp` | integer | não | [custos] Pontos-base. |

```json
{
  "id": "9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b",
  "codigo": "COT-0042",
  "titulo": "Chaveiros evento Loja Exemplo",
  "status": "aprovada",
  "versao": 2,
  "cliente": {
    "nome": "Ana Lima",
    "contato": "ana.lima@example.com"
  },
  "validade": "2026-10-31",
  "condicoes": "Pagamento 50% na aprovação e 50% na entrega.",
  "observacao": null,
  "itens": [
    {
      "id": "d3e4f5a6-b7c8-4d9e-0f1a-2b3c4d5e6f7a",
      "nome": "Chaveiro Dragão · Azul",
      "sku": "CHAV-DRG-AZ",
      "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
      "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
      "quantidade": 200,
      "preco_unitario_centavos": 1290,
      "total_centavos": 258000,
      "cor": {
        "id": "c2d3e4f5-a6b7-4c8d-9e0f-1a2b3c4d5e6f",
        "codigo": "#007",
        "nome_cliente": "Azul",
        "acabamento": "fosco"
      },
      "cor_a_combinar": false
    }
  ],
  "total_centavos": 258000,
  "desconto_centavos": 12900,
  "criado_em": "2026-10-03T14:00:00-03:00",
  "atualizado_em": "2026-10-05T09:30:00-03:00",
  "enviada_em": "2026-10-03T16:10:00-03:00",
  "aprovada_em": "2026-10-05T09:30:00-03:00"
}
```

## Outras respostas

- **400** (`dados_invalidos`): Dados, filtro, cursor ou cabeçalho inválido.
- **401** (`nao_autenticado`): Chave ausente, malformada, desconhecida, revogada ou expirada (a resposta é a mesma para todos os casos).
- **403** (`escopo_insuficiente`): Escopo insuficiente, conta bloqueada, módulo desligado ou chave suspensa.
- **404** (`nao_encontrado`): Não existe nesta conta.
- **408** (`tempo_esgotado`): O corpo do POST não chegou inteiro em 5 s.
- **409** (`status_mudou`): O status atual da cotação não é o informado em `de`. Nada mudou. Releia a cotação e decida de novo.
- **413** (`corpo_grande_demais`): Corpo acima de 64 KB.
- **415** (`tipo_nao_suportado`): Só `application/json`.
- **422** (`saldo_insuficiente`): Regra de negócio recusou (referência de outra conta ou inexistente, saldo insuficiente, quantidade fora do mínimo ou múltiplo) ou a Idempotency-Key já foi usada com outro corpo (`idempotencia_conflito`).
- **429** (`limite_excedido`): Limite de uso excedido (rajada, minuto, mês ou requisições simultâneas).
- **500** (`erro_interno`): Erro interno. O detalhe fica no log, ligado ao requisicao_id.
- **503** (`indisponivel`): API desligada, sob pressão (disjuntor aberto) ou no limite global da plataforma.

## Exemplos

**cURL**

```bash
curl -X POST "https://api.precificador3d.com.br/v1/cotacoes/9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b/status" \
  -H "Authorization: Bearer $PC3D_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data '{
  "de": "enviada",
  "para": "aprovada",
  "motivo": "Cliente aprovou por e-mail"
}'
```

**JavaScript**

```js
const resposta = await fetch('https://api.precificador3d.com.br/v1/cotacoes/9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b/status', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PC3D_CHAVE}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "de": "enviada",
    "para": "aprovada",
    "motivo": "Cliente aprovou por e-mail"
  }),
});
if (!resposta.ok) {
  const erro = await resposta.json(); // application/problem+json
  throw new Error(`${erro.codigo}: ${erro.detail} (${erro.requisicao_id})`);
}
const dados = await resposta.json();
```

**Python**

```python
import os
import uuid

import requests

resposta = requests.post(
    "https://api.precificador3d.com.br/v1/cotacoes/9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b/status",
    headers={
        "Authorization": f"Bearer {os.environ['PC3D_CHAVE']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "de": "enviada",
        "para": "aprovada",
        "motivo": "Cliente aprovou por e-mail",
    },
    timeout=10,
)
resposta.raise_for_status()
dados = resposta.json()
```
