> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ephra.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Vendas

> Cadastre e atualize clientes, exporte o relatório de vendas em CSV e estorne uma venda paga pela API.

Depois que o dinheiro entra, três coisas interessam: **quem comprou**, **o que foi vendido** e **o que precisa voltar**. O domínio de vendas cobre as três em 6 operações.

<Info>
  Os exemplos usam `$TOKEN`. Veja [Primeiros passos](/guias/primeiros-passos) se ainda não tiver um.
</Info>

## 1. Cadastre o cliente

O cadastro é por **documento**: mandar o mesmo CPF de novo atualiza o cliente existente em vez de duplicá-lo.

```bash theme={null}
curl -s -X POST https://api.ephra.io/v1/customers \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Mariana Ribeiro Alves",
    "document": "390.533.447-05",
    "email": "mariana.alves@exemplo.com.br",
    "phone": "+5521998877665",
    "mailMarketing": true,
    "address": {
      "street": "Rua Visconde de Pirajá",
      "streetNumber": "414",
      "complement": "sala 1108",
      "neighborhood": "Ipanema",
      "city": "Rio de Janeiro",
      "state": "RJ",
      "zipCode": "22410-002"
    }
  }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "id": "cmtxysj1i0000owg1gz61pago",
    "name": "Mariana Ribeiro Alves",
    "email": "mariana.alves@empresadela.com.br",
    "phone": "+5521998877665",
    "document": "39053344705",
    "documentType": "CPF",
    "instagram": null,
    "birthDate": null,
    "mailMarketing": true,
    "taxFree": false,
    "tags": ["lancamento-setembro"],
    "notes": "Pediu nota com o CNPJ dela a partir da próxima compra.",
    "address": null,
    "createdAt": "2026-09-12T05:48:39.654Z",
    "updatedAt": "2026-09-12T05:48:48.041Z"
  }
}
```

Três coisas a notar:

* O `document` volta **sem pontuação**. Mande com ou sem — a API normaliza.
* `documentType` é deduzido do tamanho: 11 dígitos viram `CPF`, 14 viram `CNPJ`.
* O campo é o `streetNumber`, não `number`. Mandar `number` reprova com `422 address.streetNumber: Required`.

## 2. Ache um cliente

```bash theme={null}
curl -s "https://api.ephra.io/v1/customers?page=1&pageSize=3&search=Mariana" \
  -H "Authorization: Bearer $TOKEN"
```

`search` procura em nome, e-mail e documento ao mesmo tempo, então serve tanto para o time de suporte quanto para uma busca por CPF.

## 3. Atualize o que mudou

`PUT` aqui é parcial: mande só os campos que mudaram.

```bash theme={null}
curl -s -X PUT https://api.ephra.io/v1/customers/cmtxysj1i0000owg1gz61pago \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "mariana.alves@empresadela.com.br",
    "phone": "+5521997766554",
    "tags": ["lancamento-setembro", "cliente-recorrente", "nota-cnpj"]
  }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "id": "cmtxysj1i0000owg1gz61pago",
    "name": "Mariana Ribeiro Alves",
    "email": "mariana.alves@empresadela.com.br",
    "phone": "+5521997766554",
    "document": "39053344705",
    "documentType": "CPF",
    "mailMarketing": true,
    "taxFree": false,
    "tags": ["lancamento-setembro", "cliente-recorrente", "nota-cnpj"],
    "notes": "Pediu nota com o CNPJ dela a partir da próxima compra.",
    "address": {
      "street": "Rua Visconde de Pirajá",
      "streetNumber": "414",
      "complement": "sala 1108",
      "neighborhood": "Ipanema",
      "city": "Rio de Janeiro",
      "state": "RJ",
      "zipCode": "22410-002"
    },
    "createdAt": "2026-09-12T05:48:39.654Z",
    "updatedAt": "2026-09-12T06:27:58.195Z"
  }
}
```

`tags` substitui a lista inteira — não acrescenta. Leia antes se quiser preservar as existentes.

## 4. Exporte o relatório de vendas

A exportação devolve o CSV **dentro do JSON**, pronto para gravar em disco.

```bash theme={null}
curl -s -X POST https://api.ephra.io/v1/transactions/export \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paid",
    "startDate": "2026-08-01T00:00:00.000Z",
    "endDate": "2026-08-31T23:59:59.000Z"
  }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "filename": "vendas-2026-09-12.csv",
    "contentType": "text/csv; charset=utf-8",
    "rowsExported": 0,
    "filtersDescription": "Período: 2026-08-01T00:00:00.000Z até 2026-08-31T23:59:59.000Z · Status: paid",
    "content": "﻿ID,Data da criação,Data do pagamento,Produto,Nome,E-mail,Telefone,CPF/CNPJ,Método,Status,Data da solicitação de reembolso,Data da execução do reembolso,Motivo de recusa,Total líquido,Total bruto"
  }
}
```

São 15 colunas fixas. O `content` começa com BOM UTF-8 (`﻿`) de propósito: sem ele o Excel brasileiro abre "Tráfego" como "TrÃ¡fego".

```bash theme={null}
curl -s -X POST https://api.ephra.io/v1/transactions/export \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"status":"paid","startDate":"2026-08-01T00:00:00.000Z","endDate":"2026-08-31T23:59:59.000Z"}' \
  | jq -r '.data.content' > vendas-agosto.csv
```

<Tip>
  `rowsExported` diz quantas linhas de dados vieram, sem contar o cabeçalho. `0` significa que o filtro não achou nada — não que a exportação falhou.
</Tip>

## 5. Estorne uma venda

O estorno é **irreversível** e devolve o dinheiro ao comprador. A `reason` fica no histórico e aparece para o time de suporte.

```bash theme={null}
curl -s -X POST https://api.ephra.io/v1/transactions/cmtxyt3780001eag1tol64iwm/refund \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Comprador desistiu dentro do prazo de garantia de 7 dias."}'
```

Só uma venda **paga** pode ser estornada. Qualquer outro estado responde `400` dizendo em que estado a venda está:

```json theme={null}
{
  "success": false,
  "message": "Apenas transações com status 'paid' podem ser reembolsadas. Status atual: pending"
}
```

<Warning>
  Esta rota estorna direto, sem passar pelo fluxo de aprovação. Quando o pedido vem do comprador pelo formulário da Ephra, ele nasce como uma solicitação e você decide — veja [Reembolsos](/guias/reembolsos). Use `POST /v1/transactions/{transactionId}/refund` quando a decisão já foi tomada fora da Ephra.
</Warning>

## Onde está a listagem de vendas?

O domínio de vendas não tem um `GET /v1/sales`. Para consultar transações uma a uma ou em página, use a superfície transacional, que já existe e continua suportada:

* [`GET /v1/transactions`](/api-reference/transacoes-listar) — lista com filtros.
* [`GET /v1/transactions/{transactionId}`](/api-reference/transacoes-consultar) — uma venda com cliente, itens e dados do Pix.

<Note>
  Essas duas rotas são anteriores à API do vendedor e **não usam o envelope `pagination`** desta documentação: respondem `totalRows`. Veja [Paginação, filtros e erros](/guias/paginacao-filtros-erros).
</Note>

## Todas as operações do domínio

<CardGroup cols={2}>
  <Card title="Clientes" icon="user" href="/api-reference/vendas/listar-clientes">
    Listar, cadastrar, consultar e atualizar.
  </Card>

  <Card title="Exportar vendas" icon="file-csv" href="/api-reference/vendas/exportar-vendas-em-csv">
    CSV de 15 colunas, filtrado por período e status.
  </Card>

  <Card title="Estornar uma venda" icon="rotate-left" href="/api-reference/vendas/reembolsar-uma-venda">
    Devolve o dinheiro de uma venda paga.
  </Card>

  <Card title="Reembolsos" icon="hand-holding-dollar" href="/guias/reembolsos">
    O fluxo com aprovação, quando o pedido parte do comprador.
  </Card>
</CardGroup>
