O que é a TrevoPay?
A TrevoPay é um gateway de pagamento PIX que nasceu de uma necessidade real: simplificar cobranças (PIX IN) e saques (PIX OUT) para infoprodutores e plataformas brasileiras. Percebemos que os meios existentes eram complexos demais — documentações confusas, processos de homologação longos e múltiplas formas de fazer a mesma coisa. Nossa resposta foi uma API que transforma isso em algo simples e direto:
// amount em CENTAVOS (int): 1990 = R$ 19,90
trevopay.charges.create({
amount: 1990,
description: 'Curso de PIX',
externalId: 'PED-123',
});REST + JSON, valores sempre em centavos (int), envelope { data, error, success } em toda resposta. Sem mágica, sem armadilhas. Veja as regras essenciais antes da primeira chamada.
Princípios da API
Baseada em intenção
Cada endpoint representa exatamente o que você lê. POST /v1/charges cria uma cobrança. POST /v1/cashouts realiza um saque. Sem aliases, sem ambiguidade.
Consistente
Toda resposta segue o padrão { data, error, success }. Se success for true, os dados estão em data. Se false, a falha está em error com { code, message }.
Idempotente
POSTs que movimentam dinheiro exigem Idempotency-Key. Reenviar com a mesma key + mesmo corpo devolve a mesma resposta — você nunca duplica cobrança nem saque.
Segura por padrão
HTTPS obrigatório, webhooks assinados com HMAC-SHA256, janela anti-replay de 5 minutos e comparação tempo-constante para evitar timing attacks.
Regras essenciais
Cinco convenções que valem para toda chamada da API — tanto em PIX IN (cobranças) quanto em PIX OUT (saques). Quebrar qualquer uma delas devolve 422 validation_error ou pior. Repetimos cada regra dentro dos endpoints específicos para você não precisar voltar aqui.
Valor sempre em centavos (int)
O campo amount é um inteiro em centavos. Nunca envie float, string formatada ou ponto/vírgula. Conversão mental:
1990 → R$ 19,90 · 1616 → R$ 16,16 · 100 → R$ 1,00 · 50000 → R$ 500,00.
Se você tem R$ 16,00 na cabeça, envie 1600. Se tem R$ 16,16, envie 1616.
Idempotency-Key obrigatória em POSTs
Todo POST /v1/charges e POST /v1/cashouts exige o header Idempotency-Key (8–200 chars). Use o id do seu pedido — reenviar com a mesma key + mesmo corpo devolve a mesma resposta. Você nunca duplica cobrança nem saque.
Webhook é a fonte de verdade
Nunca libere acesso confiando no front-end. Só libere depois de receber o webhook assinado charge.paid (ou após confirmar via GET /v1/charges/{id}). Sempre valide o HMAC-SHA256 em tempo constante antes de qualquer side-effect.
HTTPS obrigatório em produção
Toda chamada para /v1/* e todo endpoint de webhook precisam ser HTTPS. Chamadas HTTP fora de localhost retornam 400 https_required. Sem exceções.
Datas em ISO-8601 UTC, moeda BRL
Datas com sufixo Z: 2026-05-29T14:00:00Z. Moeda sempre "BRL" (PIX only). Campos em camelCase em request e response. Encoding sempre UTF-8.
Prefixos de ID padronizados
ch_ cobranças · bp_co_ saques · whsec_ signing secret de webhook · pk_test_ / sk_test_ / pk_live_ / sk_live_ API keys. Use o prefixo pra rotear ids no seu sistema.
"amount": 19.90 achando que vai cobrar R$ 19,90. Errado — isso vira 19 centavos (R$ 0,19). O certo é "amount": 1990 (inteiro, centavos).
O que você pode fazer
Recursos disponíveis na API v1. Todos prontos em produção, com versões de teste no sandbox.
Receber via PIX
Gere QR Code PIX e copia-e-cola para cobrar seus clientes de forma instantânea, com confirmação por webhook.
Realizar saques PIX
Pague afiliados, prestadores ou repasse valores ao cliente final via cashout PIX programático.
Consultar transações
Polling de fallback para casos em que o webhook ainda não chegou, ou reconciliação em lote.
Receber webhooks
Eventos assinados em tempo real: charge.paid, charge.expired, cashout.confirmed e mais.
Testar no sandbox
Ambiente de testes paralelo. Crie cobranças, simule pagamentos e dispare webhooks sem mover um centavo.
Idempotência nativa
Reenvie a mesma requisição sem medo. Mesma Idempotency-Key + mesmo corpo = mesma resposta.
UTMs no checkout
Envie UTMs na criação da cobrança e receba de volta no webhook — para fechar o ciclo do seu funil.
Chaves com escopo
Emita chaves de leitura ou criação separadas, restritas por escopo: CHARGE:READ, CASHOUT:CREATE, etc.
Primeiros passos
Em três passos você cria uma cobrança e simula o pagamento no sandbox — sem dinheiro real.
Chaves de API
Crie sua conta e gere suas credenciais pk_test_ / sk_test_ em menos de 1 minuto.
Ambiente de testes
Entenda como funciona o sandbox: criar cobranças, simular pagamentos e disparar webhooks fictícios.
Configurar webhooks
Cadastre o endpoint, valide a assinatura HMAC e receba eventos em tempo real.
Indo para produção
Checklist para trocar sk_test_ por sk_live_ sem surpresas.
Autenticação
Toda chamada de servidor usa o header Authorization: Bearer SUA_SECRET. Há dois ambientes:
| Ambiente | Chaves | Comportamento |
|---|---|---|
| Teste | pk_test_… / sk_test_… | Nunca movimenta dinheiro real. Use para integrar. |
| Produção | pk_live_… / sk_live_… | Cobranças reais, liquidadas pelo PSP. |
Escopos
Cada chave pode ter um subconjunto de escopos. Por padrão a chave criada no painel recebe todos os escopos do plano.
| Escopo | Permite |
|---|---|
| CHARGE:CREATE | Criar cobranças PIX. |
| CHARGE:READ | Consultar cobranças. |
| CASHOUT:CREATE | Criar saques PIX. |
| CASHOUT:READ | Consultar saques. |
Idempotência
POSTs que movimentam dinheiro (/v1/charges e /v1/cashouts) exigem o header Idempotency-Key. Isso protege você contra cobranças duplicadas em casos de retry.
- String única por operação, de 8 a 200 caracteres.
- Mesma key + mesmo corpo: devolve a mesma resposta (não duplica).
- Mesma key + corpo diferente:
409 idempotency_conflict. - Outra requisição em voo com a mesma key:
409 idempotency_in_progress. - Reaproveitável por 24h; depois disso é liberada.
Sandbox / Dev mode
Com sk_test_, crie a cobrança normalmente — o brCode e o QR vêm em formato válido (fictícios — não funcionam no app do banco). Para simular o pagamento e disparar o webhook de saída:
curl -X POST https://api.treevopay.com/sandbox/simulate-payment/ch_xxx \ -H "Authorization: Bearer sk_test_SUA_CHAVE"
Dica: passe ?silent=1 para marcar pago sem disparar webhook e testar a reconciliação ativa.
Cashout em sandbox roda livre — mode=test sempre retorna status=confirmed sem bater no PSP.
Criar cobrança PIX (PIX IN)
POST /v1/chargesCria uma cobrança PIX e retorna o copia-e-cola e o QR. O header Idempotency-Key é obrigatório.
amountem centavos (int).1990= R$ 19,90,1616= R$ 16,16,100= R$ 1,00. Nunca envie19.90nem"19,90"— vira 19 centavos.Idempotency-Keyobrigatório (8–200 chars). Use o id do seu pedido. Mesma key + mesmo corpo = mesma cobrança (não duplica).- HTTPS obrigatório. Chamada HTTP fora de localhost devolve
400 https_required. - Só libere acesso pelo webhook
charge.paid(HMAC validado) — nunca confie só no retorno do front.
Headers
| Header | Descrição |
|---|---|
| Authorization obrigatório | Bearer sk_test_… ou sk_live_… |
| Content-Type obrigatório | application/json |
| Idempotency-Key obrigatório | String única (8–200). Repetir com mesmo corpo = mesma cobrança. |
Parâmetros (body JSON)
| Campo | Tipo | Descrição |
|---|---|---|
| amount obrigatório | int | Valor em centavos. Mín 100, máx 100000000. |
| description | string | Nome do produto na hora (até 255). |
| externalId | string | Seu identificador interno (até 120). |
| customer | object | { name, email, taxId, cellphone } — opcional. |
| utm | object | { source, medium, campaign, term, content } — ecoado no webhook. |
Exemplo
curl -X POST https://api.treevopay.com/v1/charges \
-H "Authorization: Bearer sk_test_SUA_CHAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-123" \
-d '{"amount":1990,"description":"Curso","externalId":"PED-123"}'Resposta 201
{
"success": true,
"data": {
"id": "ch_2f1a8c9d4e5b6a7c8d9e0f12",
"amount": 1990,
"currency": "BRL",
"status": "pending",
"description": "Curso",
"externalId": "PED-123",
"brCode": "00020101…6304ABCD",
"brCodeBase64": "data:image/png;base64,iVBOR…",
"expiresAt": "2026-05-29T14:00:00Z",
"mode": "test"
},
"error": null
}Consultar cobrança
GET /v1/charges/{id}data.status é um de: pending, paid, expired, failed, refunded. O status é monotônico: paid nunca volta para pending.
curl https://api.treevopay.com/v1/charges/ch_xxx \ -H "Authorization: Bearer sk_test_SUA_CHAVE"
Realizar saque PIX (PIX OUT)
POST /v1/cashoutsSaque PIX programático (B2B/B2C). Útil para plataformas que precisam pagar prestadores, afiliados ou repassar valores ao cliente final.
amountem centavos (int, ≥ 1).50000= R$ 500,00,1616= R$ 16,16. Nunca envie float ou string com vírgula — o PSP rejeita.pixKey+pixKeyTypeprecisam casar. Tipocpf? envie 11 dígitos sem máscara.cnpj? 14 dígitos.phone? só dígitos com DDD (ex.:11999998888).email? em minúsculas.random? UUID v4.Idempotency-Keyobrigatório (8–200). Use o id do payout — mesma key + mesmo corpo nunca paga 2x.- Produção exige liberação:
bspay_cashout_enabled=1no painel admin. Desligado devolve503 cashout_disabled. Sandbox (sk_test_) roda livre. - Resposta 202 ≠ saque feito. O 202 só confirma que o PSP aceitou. A liquidação real vem no webhook
cashout.confirmedoucashout.failed.
Parâmetros (body JSON)
| Campo | Tipo | Descrição |
|---|---|---|
| amount obrigatório | int | Valor em centavos (≥ 1). |
| pixKey obrigatório | string | Chave PIX do destinatário (até 200). |
| pixKeyType obrigatório | string | cpf · cnpj · email · phone · random |
| externalId | string | Seu identificador (até 64). Determinístico se omitido. |
| description | string | Descrição livre (até 140). |
Exemplo
curl -X POST https://api.treevopay.com/v1/cashouts \
-H "Authorization: Bearer sk_live_SUA_CHAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: saque-afiliado-789" \
-d '{
"amount": 50000,
"pixKey": "joao@exemplo.com",
"pixKeyType": "email",
"externalId": "PAYOUT-789",
"description": "Comissao afiliado"
}'Resposta 202
{
"success": true,
"data": {
"id": "bp_co_a1b2c3d4e5f6a7b8",
"amount": 50000,
"currency": "BRL",
"status": "pending",
"externalId": "PAYOUT-789",
"transactionId": "TXN-PSP-99887766",
"pixKey": "joao@exemplo.com",
"pixKeyType": "email",
"description": "Comissao afiliado",
"failureReason": null,
"mode": "live",
"requestedAt": "2026-05-29T14:00:00Z",
"confirmedAt": null
},
"error": null
}O HTTP 202 indica que o saque foi aceito e enviado ao PSP. A confirmação final vem via webhook cashout.confirmed ou cashout.failed.
Consultar saque
GET /v1/cashouts/{id}Status possíveis: pending (enviado ao PSP), confirmed (liquidado na chave do destinatário), failed (ver failureReason).
curl https://api.treevopay.com/v1/cashouts/bp_co_xxx \ -H "Authorization: Bearer sk_live_SUA_CHAVE"
Webhooks
Cadastre uma URL no painel. Quando a cobrança é paga (ou o saque é confirmado), enviamos um POST assinado para você. A fonte de verdade é o webhook validado no seu servidor — nunca confie no front-end.
Eventos
| Evento | Quando |
|---|---|
| charge.paid | Pagamento confirmado. |
| charge.expired | Cobrança expirou sem pagamento. |
| charge.failed | Falha no processamento. |
| charge.refunded | Pagamento reembolsado. |
| cashout.confirmed | Saque liquidado. |
| cashout.failed | Saque falhou (ver failureReason). |
Headers enviados
| X-Trevo-Event | Nome do evento. |
| X-Trevo-Timestamp | Epoch do envio (anti-replay). |
| X-Trevo-Signature | HMAC-SHA256 em hex. |
| X-Trevo-Delivery | ID único da entrega (deduplicação). |
Validar a assinatura
A assinatura é HMAC-SHA256(timestamp + "." + corpo_cru, signing_secret). Use sempre comparação tempo-constante.
<?php
$secret = 'whsec_SEU_SIGNING_SECRET';
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_TREVO_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_TREVO_SIGNATURE'] ?? '';
// rejeita replay (> 5 min)
if (abs(time() - (int)$ts) > 300) { http_response_code(400); exit; }
$expected = hash_hmac('sha256', $ts . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) { http_response_code(401); exit; }
$evt = json_decode($body, true);
// libere o acesso do cliente aqui — $evt['data']['externalId'] etc.
http_response_code(200);X-Trevo-Delivery para deduplicar.Indo para produção
- Troque
sk_test_porsk_live_em todos os ambientes. - Use sempre HTTPS — nunca aceite webhook em endpoint HTTP.
- Valide a assinatura HMAC do webhook antes de qualquer side-effect.
- Use
hash_equals/timingSafeEqual/hmac.compare_digest, nunca==. - Use a
Idempotency-Keypor pedido para evitar cobranças duplicadas. - Trate 429 com backoff + jitter. Não retentar 4xx (exceto 429).
- Monitore o status na página status.treevopay.com.
Erros
Em erro, data é null e error traz { code, message }. O HTTP status indica a categoria, o code indica a causa específica.
| HTTP | code | Significado |
|---|---|---|
| 400 | idempotency_key_required | Faltou o header Idempotency-Key. |
| 400 | invalid_json | Body não é JSON válido. |
| 400 | https_required | Chamada via HTTP fora de localhost. |
| 401 | invalid_credentials | Chave inválida ou malformada. |
| 401 | key_revoked | Chave revogada no painel. |
| 403 | insufficient_scope | A chave não tem o escopo necessário. |
| 404 | charge_not_found | Cobrança não existe para esta conta. |
| 404 | cashout_not_found | Saque não existe para esta conta. |
| 409 | idempotency_conflict | Mesma Idempotency-Key com corpo diferente. |
| 409 | idempotency_in_progress | Mesma key em processamento. |
| 422 | validation_error | Payload inválido (ex.: amount ≤ 0). |
| 429 | rate_limited | Excedeu 100 req/min. Use Retry-After. |
| 501 | cashout_not_supported | Provider ativo não suporta cashout via API. |
| 503 | cashout_disabled | Cashout live desabilitado no painel admin. |
Saiba mais sobre a TrevoPay
Pronto para integrar?
Crie sua conta TrevoPay grátis, gere chaves sk_test_ e dispare sua primeira cobrança PIX em menos de 5 minutos. Sem cartão, sem burocracia.