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

# Antes de ir pra produção

> A lista curta do que costuma quebrar no primeiro dia com dinheiro de verdade.

Você testou em sandbox e funcionou. Estes são os pontos que sandbox não pega.

## Segurança

> [accordion] A chave live não está no bundle do front
>
> Procure por `ps_live_` no build final, não só no código. Um `console.log` esquecido ou
> uma variável sem prefixo de servidor já entrega a chave.
>
> Se ela estiver exposta, alguém pode criar cobrança em seu nome e, com [PIX saindo
> na hora](https://docs.purin.cash/guias/saques.md#quando-o-pix-sai-na-hora), mandar dinheiro pra fora.

> [accordion] O webhook valida a assinatura
>
> A sua `callbackUrl` é pública. Sem [validar o
> `X-Webhook-Signature`](https://docs.purin.cash/webhooks/assinatura), qualquer pessoa manda um JSON com
> `"status": "paid"` e leva o produto de graça.
>
> Confira também que você está assinando o **corpo cru**, antes do parse. Um
> `express.json()` no lugar errado quebra a validação de um jeito que passa em teste e
> falha em produção.

> [accordion] O valor é conferido antes da entrega
>
> Não basta o `status` ser `paid`. Compare o `amountCents` recebido com o valor que você
> esperava para aquele pedido antes de liberar qualquer coisa.

> [accordion] O webhook secret está fora do repositório
>
> Variável de ambiente ou cofre. Se vazou, regenere no painel: o antigo para de funcionar
> na hora.

## Confiabilidade

> [accordion] O handler é idempotente
>
> Webhook é reentregue quando a entrega falha, e a mesma confirmação pode chegar mais de
> uma vez. Deduplique pelo header `X-Webhook-Id`, que é estável entre as tentativas.
>
> O teste é simples: mande o mesmo payload duas vezes e veja se o cliente recebe o
> produto duas vezes.

> [accordion] Você responde 200 rápido e processa depois
>
> O timeout é de 5 segundos. Se o seu handler manda e-mail, gera licença e escreve em
> três tabelas antes de responder, ele vai estourar e você vai receber reentrega de
> coisa que já processou.
>
> Grave o evento, responda `200`, processe em fila.

> [accordion] Existe reconciliação além do webhook
>
> Webhook é notificação, não fonte da verdade. Tenha um job que varre pedidos parados em
> `pending` há mais de uma hora e confirma o estado por `GET`.

> [accordion] Você não faz retry de 202 e processing
>
> Em [saques](https://docs.purin.cash/guias/saques.md), `202` e `status: "processing"` significam que o dinheiro
> pode já ter saído. Reenviar paga duas vezes.

## Configuração da conta

**1. Chave PIX verificada**

Sem verificação, o primeiro saque devolve `403`. Resolva isso antes de precisar do
dinheiro, não depois.

**2. URL de webhook cadastrada no painel**

Os webhooks de [pedido](https://docs.purin.cash/webhooks/pedidos.md) e de [saque](https://docs.purin.cash/webhooks/saques.md) usam a URL
configurada na conta, não a `callbackUrl` da cobrança.

**3. Valor mínimo conferido**

O painel permite subir o mínimo da loja acima de R\$ 0,80. Se o seu produto mais barato
fica abaixo dele, a cobrança falha em produção e passava em sandbox.

**4. Carteira LTC configurada, se for usar cripto**

Sem carteira, `paymentMethod: "ltc"` devolve `503`.

## Operação

> [card] Log com o tripé certo
>
> Código HTTP, corpo do erro e `paymentId`. Com esses três, uma dúvida
> [no Discord](https://discord.gg/8eyQQFZZxY) vira uma resposta em vez de cinco.

> [card] [Alerta de disputa](https://docs.purin.cash/guias/disputas.md)
>
> Rode `GET /v1/disputes?status=aberta` diariamente. Contestação tem prazo.

> [card] [Uma chave por serviço](https://docs.purin.cash/guias/autenticacao.md)
>
> Dá pra revogar uma sem derrubar o resto, e dá pra saber quem gastou o limite.

> [card] [Backoff no cliente](https://docs.purin.cash/guias/limites.md)
>
> Com jitter. Sem ele, seus workers batem no `429` todos juntos.

## O teste final

Faça uma venda real de valor baixo, do início ao fim: cobrança, pagamento, webhook,
entrega e saque. É o único teste que cobre configuração de conta, e leva dez minutos.

> [card] [Travou em algum ponto?](https://discord.gg/8eyQQFZZxY)
>
> Chama no Discord com o código HTTP, o corpo do erro e o `paymentId`. Costuma sair na
> primeira resposta.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.