API da Cherryfy
Documentação da API
Tudo o que você precisa para ligar o seu sistema à Cherryfy: criar cobranças Pix, receber o aviso de pagamento, consultar a carteira e enviar Pix direto do seu servidor.
Como funciona, em três passos
- 1Crie a credencial
No painel, em Configurações › Chave API, gere o Token e o Secret da sua integração.
- 2Gere a cobrança
Envie o valor e os dados do pagador e mostre o QR code para o seu cliente.
- 3Confirme o pagamento
Receba o aviso na sua URL de
postbacke confirme com a consulta da transação antes de liberar o pedido.
Convenções
- Requisições e respostas em JSON (UTF-8). Envie
Content-Type: application/jsonnas chamadas com corpo eAccept: application/jsonem todas. - Valores em reais, com ponto decimal:
25.00. - Identificadores como
idTransactionsão texto. Guarde como string, sem presumir formato ou tamanho. - A API fala com o seu servidor. Nunca chame as rotas autenticadas a partir de um navegador ou aplicativo.
- Não existe ambiente de testes separado: toda chamada vale de verdade. Teste com valores pequenos.
Os exemplos em PHP usam a extensão cURL; os de Node.js, o fetch nativo (Node 18 ou mais novo, em módulo ES); os de Python, a biblioteca requests. Em todos, as credenciais vêm de variáveis de ambiente.
Início rápido #
Da credencial ao primeiro Pix confirmado, em quatro passos.
- 1Pegue o Token e o Secret
Painel › Configurações › Chave API › Nova credencial. O Secret aparece uma única vez: guarde na hora, em um cofre de senhas ou variável de ambiente.
- 2Crie a cobrança
Chame
POST /wallet/deposit/payment. A resposta traz oidTransactione oqrcode(copia e cola). - 3Mostre o QR code
Exiba o copia e cola e a imagem do QR code para o seu cliente pagar no aplicativo do banco.
- 4Confirme
Quando o aviso chegar na sua URL de
postback, consultePOST /wallet/transaction. Só libere o pedido comstatusigual aPAID_OUT.
As chamadas acontecem na sua conta de verdade. Para validar a integração, gere uma cobrança de valor baixo e pague você mesmo.
curl -X POST \
"https://app.cherryfy.co/api/wallet/deposit/payment" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 25.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/deposit/payment');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 25.00,
'debtor_name' => 'Marina Souza',
'email' => '[email protected]',
'debtor_document_number' => '12345678909',
'phone' => '11999999999',
'method_pay' => 'pix',
'postback' => 'https://seusite.com.br/webhooks/pix',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/deposit/payment`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
amount: 25.00,
debtor_name: 'Marina Souza',
email: '[email protected]',
debtor_document_number: '12345678909',
phone: '11999999999',
method_pay: 'pix',
postback: 'https://seusite.com.br/webhooks/pix',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/deposit/payment",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"amount": 25.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"qrcode": "00020126580014br.gov.bcb.pix...6304A1B2",
"qr_code_image_url": "https://exemplo.com/qr/7c1f2b9e.png",
"qr_code_base64": "iVBORw0KGgoAAAANSUhEUgAA..."
}curl -X POST \
"https://app.cherryfy.co/api/wallet/transaction" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/transaction');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'idTransaction' => '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/transaction`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
idTransaction: '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/transaction",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
},
timeout=30,
)
print(resposta.status_code, resposta.json())Autenticação #
Cada integração se identifica com um par de credenciais da conta: o Token, que diz quem está chamando, e o Secret, que prova que é você.
Onde gerar
No painel, em Configurações › Chave API, clique em Nova credencial. O Secret é mostrado uma única vez, logo depois de criar. Se perder, use Gerar novo na mesma tela: o Secret antigo para de funcionar na hora.
Como enviar
Envie as credenciais nos cabeçalhos da requisição:
| Cabeçalho | Valor |
|---|---|
X-Api-Tokenstringobrigatório | O Token da credencial. |
X-Api-Secretstringobrigatório | O Secret da credencial. |
Content-Typestring | application/json, nas chamadas com corpo. |
Acceptstring | application/json, para receber os erros sempre em JSON. |
Quem já envia token e secret como campos do corpo JSON continua funcionando. Em integrações novas, use os cabeçalhos. Se os dois chegarem, vale o cabeçalho.
Uma chamada com secret na query string é recusada com 400. Endereços ficam gravados em histórico, proxies e logs.
Quando a autenticação falha
| HTTP | Motivo |
|---|---|
| 400 | Token ou Secret não foram enviados. |
| 400 | O Secret veio na URL. |
| 401 | Token ou Secret inválidos. |
| 401 | A conta ainda não foi aprovada, ou está inativa. |
curl "https://app.cherryfy.co/api/wallet/balance" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Accept: application/json"<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Accept: application/json',
],
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/balance`, {
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
Accept: 'application/json',
},
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.get(
f"{BASE}/wallet/balance",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"error": "Token ou Secret ausentes",
"message": "Você precisa fornecer tanto o token quanto o secret."
}{
"status": "error",
"message": "Não envie o secret na URL. Use os cabeçalhos X-Api-Token e X-Api-Secret."
}{
"status": "error",
"message": "Token ou Secret inválidos"
}{
"status": "error",
"message": "Usuário com conta pendente de aprovação."
}Ambiente #
Existe um único ambiente, o de produção. Todas as rotas desta documentação partem do endereço base:
https://app.cherryfy.co/api
| Rota | O que faz | Credencial | Limite |
|---|---|---|---|
POST/wallet/deposit/payment | Gera uma cobrança Pix. | Sim | 60 por minuto |
POST/status | Devolve o status de uma cobrança. | Não | 20 por minuto |
POST/pixout | Envia um Pix a partir do saldo. | Sim, e IP permitido | 30 por minuto |
GET/wallet/balance | Consulta o saldo da carteira. | Sim | 60 por minuto |
POST/wallet/transaction | Consulta uma transação da conta. | Sim | 60 por minuto |
Use sempre HTTPS. Os limites são explicados em Limites de requisição.
Erros e códigos de retorno #
A API responde com os códigos HTTP abaixo. Decida o que fazer pelo código; use o campo message para registrar e mostrar o motivo.
| HTTP | Quando acontece |
|---|---|
| 200 | Deu certo. |
| 400 | Credenciais ausentes, ou Secret enviado na URL. |
| 401 | Credenciais inválidas ou conta pendente de aprovação. Também é o código das regras de valor: abaixo do mínimo e saldo insuficiente. |
| 403 | Saque vindo de um IP fora da lista de permitidos, ou com baasPostbackUrl igual a web. |
| 404 | A transação consultada não existe nesta conta. |
| 422 | Campo obrigatório faltando ou com formato inválido. O corpo traz errors, com as mensagens de cada campo. |
| 429 | Limite de requisições atingido. Espere o tempo do cabeçalho Retry-After. |
| 500 | Falha interna ou no processador do pagamento. Tente de novo mais tarde; em saque, repita com o mesmo external_id para não pagar duas vezes. |
Formato do corpo de erro
O formato padrão tem status igual a error, uma message legível e, nas validações, o objeto errors.
Três respostas têm outro formato: credenciais ausentes usam a chave error; o bloqueio por IP devolve success: false e o client_ip que o servidor enxergou; e o limite de requisições traz só message. Por isso, confie primeiro no código HTTP.
{
"status": "error",
"message": "Erro de validação",
"errors": {
"email": [
"O campo email é obrigatório."
],
"phone": [
"O campo phone é obrigatório."
]
}
}{
"status": "error",
"message": "Token ou Secret inválidos"
}{
"success": false,
"message": "IP não autorizado para realizar saques",
"client_ip": "203.0.113.10"
}{
"status": "error",
"message": "Transação não encontrada nesta conta."
}{
"message": "Too Many Attempts."
}{
"status": "error",
"message": "Nenhum adquirente configurado."
}Limites de requisição #
Cada rota aceita um número máximo de chamadas por minuto. Passando do teto, a resposta é 429 até a janela de um minuto virar.
| Rota | Teto por minuto |
|---|---|
POST /wallet/deposit/payment | 60 |
GET /wallet/balance | 60 |
POST /wallet/transaction | 60 |
POST /pixout | 30 |
POST /status | 20 |
Como a contagem funciona
- A contagem é por IP de origem, em janelas de um minuto.
- Cada rota tem a sua própria contagem. A exceção são as duas consultas da carteira,
GET /wallet/balanceePOST /wallet/transaction, que somam juntas no mesmo teto de 60. - Toda resposta traz
X-RateLimit-LimiteX-RateLimit-Remaining. No 429 vêm tambémRetry-After, em segundos, eX-RateLimit-Reset, em tempo Unix.
Em vez de perguntar o status a cada segundo, espere o webhook e faça uma única consulta para confirmar. Em caso de 429, aguarde o Retry-After antes de tentar outra vez.
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
Retry-After: 60
X-RateLimit-Reset: 1790770129
{
"message": "Too Many Attempts."
}Segurança #
A API movimenta dinheiro. Estas são as proteções que existem e o que a sua integração precisa fazer para que elas funcionem.
HTTPS, sempre
Chame a API somente por https:// e publique as suas URLs de aviso também em HTTPS.
Credenciais só no servidor
Token e Secret vão nos cabeçalhos e ficam em variável de ambiente ou cofre de segredos. Nunca em código de front-end, aplicativo, repositório ou URL.
Secret aparece uma vez só
O Secret aparece uma vez, na criação. Se suspeitar de vazamento, gere um novo no painel: o anterior deixa de valer na hora.
Saque só de IPs permitidos
O saque pela API exige que o IP de origem esteja em Perfil › Segurança › IPs permitidos. Sem IP cadastrado, todo saque pela API é recusado.
Limite por rota
Cada rota tem um teto de chamadas por minuto. Quem passa do teto recebe 429. Veja Limites de requisição.
Confirme todo aviso
Os webhooks não são assinados. Antes de liberar produto ou saldo, confirme a transação com POST /wallet/transaction.
Trate avisos repetidos
Responda 200 rápido e processe cada idTransaction uma única vez. O mesmo aviso pode chegar mais de uma vez.
Painel com 2 etapas e PIN
No painel, o login pode exigir o código de um app autenticador, e o saque pede um PIN de 6 dígitos, com bloqueio de até 15 minutos depois de 5 erros.
Não há assinatura nos webhooks nem ambiente de testes. Por isso três cuidados são obrigatórios: confirmar todo aviso pela API, deduplicar por idTransaction e mandar um external_id seu em todo saque. Se a chamada de saque cair no meio, repetir com o mesmo external_id devolve o saque já criado em vez de pagar de novo.
Webhooks #
Um webhook é um POST em JSON que a Cherryfy faz no seu servidor quando algo muda. Existem dois tipos:
| Tipo | Para onde vai | Quando dispara |
|---|---|---|
| Por transação | Para a URL que você manda em cada chamada: postback na cobrança, baasPostbackUrl no saque. | Quando a cobrança é paga ou estornada, e quando o saque é concluído ou falha. |
| Da conta | Para a URL cadastrada em Configurações › Webhooks. | Nas vendas do checkout de produtos: pedido gerado e pedido pago. |
O que o seu endpoint precisa fazer
- Aceitar
POSTcomContent-Type: application/jsonem uma URL pública, em HTTPS. - Responder com um código
2xxem poucos segundos. O processamento pesado fica para depois da resposta. - Ser idempotente: o mesmo aviso pode chegar mais de uma vez.
- Não confiar no corpo recebido. Use o
idTransactionpara confirmar pela API.
Cada aviso é enviado uma única vez, no momento do evento, com 15 segundos de espera pela sua resposta. Não há reenvio: se o seu servidor estiver fora do ar, o aviso se perde. Tenha uma rotina que consulta as transações que continuam em aberto.
Pix recebido #
Enviado para a URL de postback da cobrança quando o pagamento é confirmado. Nesse momento a cobrança passa para PAID_OUT e o valor líquido entra no saldo. O aviso sai depois de o saldo ser gravado: a consulta da transação feita na hora já mostra PAID_OUT.
| Campo | Descrição |
|---|---|
statusstring | paid quando a cobrança foi paga. refunded quando um Pix já pago foi devolvido ao pagador (estorno ou MED): nesse caso o líquido sai do saldo e a cobrança passa para REFUNDED. |
idTransactionstring | O mesmo identificador devolvido na criação da cobrança. |
typeTransactionstring | PIX no pagamento; PIX_REFUND no estorno. |
methodstring | Meio da cobrança: pix ou crypto. Só no pagamento. |
amountnumber | Valor bruto da cobrança. |
deposito_liquidonumber | Valor que entrou no saldo (bruto menos a taxa da sua conta). |
debtor_namestring | Nome do pagador informado na cobrança. |
emailstring | E-mail do pagador. |
debtor_document_numberstring | CPF ou CNPJ do pagador. |
phonestring | Telefone do pagador. |
endToEndstring ou null | Identificador da transação no Pix, quando o processador informa. |
created_atstring | Criação da cobrança, em ISO 8601 (UTC). |
paid_atstring | Confirmação do pagamento, em ISO 8601 (UTC). |
split_processedboolean | true quando a cobrança foi criada com split. |
split_amountnumber | Valor bruto multiplicado pelo percentual do split. É uma referência: o repasse efetivo é calculado sobre o valor líquido. |
split_recipientstring ou null | E-mail da conta que recebe o split. |
refunded_atstring | Só no estorno: momento da devolução, em ISO 8601 (UTC). |
Use status, idTransaction e typeTransaction para saber o que aconteceu. Valor, líquido, taxa e pagador: confirme na consulta da transação, nunca pelo corpo do aviso. No estorno, os dados do pagador não vêm.
{
"status": "paid",
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"typeTransaction": "PIX",
"method": "pix",
"amount": 25,
"deposito_liquido": 23.75,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"endToEnd": "E12345678202609301500410000000001",
"created_at": "2026-09-30T14:58:03.000000Z",
"paid_at": "2026-09-30T15:00:41.000000Z",
"split_processed": false,
"split_amount": 0,
"split_recipient": null
}{
"status": "refunded",
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"typeTransaction": "PIX_REFUND",
"amount": 25,
"deposito_liquido": 23.75,
"endToEnd": "E12345678202609301500410000000001",
"refunded_at": "2026-10-01T12:10:05.000000Z"
}Saque #
Enviado para a baasPostbackUrl do saque quando o processador confirma a transferência ou a recusa. Uma única tentativa, com 15 segundos de espera pela sua resposta.
| Campo | Descrição |
|---|---|
statusstring | paid quando o Pix foi enviado. failed quando o processador recusou a transferência: o saque passa para REJECTED e o valor volta para o saldo. |
idstring | O id devolvido por POST /pixout. |
idTransactionstring | O mesmo valor de id. |
typeTransactionstring | Sempre PIX. |
amountnumber | Valor do saque. |
cash_out_liquidonumber | Valor enviado ao beneficiário. |
pix_keystring | Chave Pix de destino. |
pix_key_typestring | Tipo da chave. |
beneficiary_namestring | Nome registrado no saque. |
beneficiary_documentstring | Documento registrado no saque. |
endToEndstring ou null | Identificador da transferência no Pix, quando o processador informa. null na falha. |
messagestring ou null | Motivo informado pelo processador quando o saque falha. null quando pago. |
datestring | Data do pedido, no formato AAAA-MM-DD HH:MM:SS. |
timestampstring | Momento do envio do aviso, em ISO 8601 (UTC). |
O processador pode demorar para confirmar. Se nada chegar em alguns minutos, consulte a transação pelo id: os status finais são PAID_OUT (enviado) e REJECTED (não enviado, valor devolvido ao saldo). Enquanto estiver PENDING, aguarde.
{
"status": "paid",
"id": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"idTransaction": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"typeTransaction": "PIX",
"amount": 50,
"cash_out_liquido": 50,
"pix_key": "12345678909",
"pix_key_type": "CPF",
"beneficiary_name": "Sua Empresa LTDA",
"beneficiary_document": "12345678909",
"endToEnd": "E12345678202609301500120000000002",
"message": null,
"date": "2026-09-30 12:00:00",
"timestamp": "2026-09-30T15:00:12.000000Z"
}{
"status": "failed",
"message": "Invalid Pix Entry",
"endToEnd": null,
"id": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"idTransaction": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"typeTransaction": "PIX",
"amount": 50,
"cash_out_liquido": 50,
"pix_key": "12345678909",
"pix_key_type": "CPF",
"beneficiary_name": "Sua Empresa LTDA",
"beneficiary_document": "12345678909",
"date": "2026-09-30 12:00:00",
"timestamp": "2026-09-30T15:00:12.000000Z"
}Webhooks da conta #
Em Configurações › Webhooks você cadastra uma URL e escolhe os eventos que ela recebe. Eles acompanham as vendas feitas pelo checkout de produtos da Cherryfy e levam os dados do comprador, úteis para CRM, e-mail e recuperação de carrinho.
| Evento | Quando dispara | status no corpo |
|---|---|---|
Pix gerado (gerado) | O comprador gera o pedido no checkout. | pendente |
Pix pago (pago) | O pagamento do pedido é confirmado. | pago |
| Campo | Descrição |
|---|---|
nomestring | Nome do comprador. |
cpfstring | CPF do comprador, só dígitos. |
telefonestring | Telefone do comprador, só dígitos. |
emailstring | E-mail do comprador. |
statusstring | pendente ou pago. |
Uma cobrança gerada com POST /wallet/deposit/payment avisa somente a URL de postback daquela cobrança. Os webhooks da conta não trazem idTransaction nem valor.
{
"nome": "Marina Souza",
"cpf": "12345678909",
"telefone": "11999999999",
"email": "[email protected]",
"status": "pendente"
}{
"nome": "Marina Souza",
"cpf": "12345678909",
"telefone": "11999999999",
"email": "[email protected]",
"status": "pago"
}Como confirmar um aviso #
Os avisos não são assinados: nada no corpo prova que ele veio da Cherryfy. Qualquer pessoa que descubra a sua URL consegue mandar um POST igual. Por isso o aviso serve só como gatilho, e a verdade vem da API.
- 1Responda
200Devolva a resposta na hora. Não segure a conexão enquanto processa.
- 2Pegue só o
idTransactionIgnore o resto do corpo para decidir qualquer coisa.
- 3Consulte a transação
Chame
POST /wallet/transactioncom as suas credenciais. A consulta só enxerga transações da sua conta. - 4Confira status e valor
Para Pix recebido, exija
typeigual acash_in,statusigual aPAID_OUTe oamountque você esperava para aquele pedido. - 5Libere uma única vez
Marque o
idTransactioncomo processado no seu banco. Se o aviso chegar de novo, não faça nada.
Dica: use um caminho difícil de adivinhar na URL de aviso (por exemplo, com um identificador aleatório). Isso reduz ruído, mas não substitui a confirmação.
# Simule o aviso no SEU endpoint de testes.
# Repare: qualquer um consegue mandar este POST, por isso o
# receptor confirma pela API antes de liberar qualquer coisa.
curl -X POST "https://seusite.com.br/webhooks/pix" \
-H "Content-Type: application/json" \
-d '{
"status": "paid",
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"typeTransaction": "PIX"
}'<?php
// webhook-pix.php: recebe o aviso e confirma pela API antes de liberar
$aviso = json_decode(file_get_contents('php://input'), true) ?: [];
$id = $aviso['idTransaction'] ?? null;
http_response_code(200); // responda rápido, com 2xx
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request(); // no PHP-FPM, devolve a resposta antes da consulta
}
if (!is_string($id) || $id === '') {
exit;
}
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/transaction');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['idTransaction' => $id]),
]);
$consulta = json_decode(curl_exec($ch), true);
$t = $consulta['transaction'] ?? null;
if ($t && $t['type'] === 'cash_in' && $t['status'] === 'PAID_OUT') {
// Aqui: libere o pedido UMA vez por idTransaction,
// conferindo se $t['amount'] é o valor que você esperava.
error_log('Pix confirmado: ' . $t['idTransaction'] . ' R$ ' . $t['amount']);
}import http from 'node:http';
const BASE = 'https://app.cherryfy.co/api';
async function confirmar(idTransaction) {
const resposta = await fetch(`${BASE}/wallet/transaction`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ idTransaction }),
});
const dados = await resposta.json();
return dados.transaction ?? null;
}
http.createServer((req, res) => {
let corpo = '';
req.on('data', (parte) => { corpo += parte; });
req.on('end', async () => {
res.writeHead(200).end(); // responda rápido, com 2xx
let aviso = {};
try { aviso = JSON.parse(corpo); } catch { return; }
if (typeof aviso.idTransaction !== 'string') return;
const t = await confirmar(aviso.idTransaction);
if (t && t.type === 'cash_in' && t.status === 'PAID_OUT') {
// Aqui: libere o pedido UMA vez por idTransaction,
// conferindo se t.amount é o valor que você esperava.
console.log('Pix confirmado:', t.idTransaction, t.amount);
}
});
}).listen(3000);import json
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
import requests
BASE = "https://app.cherryfy.co/api"
def confirmar(id_transacao):
resposta = requests.post(
f"{BASE}/wallet/transaction",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={"idTransaction": id_transacao},
timeout=30,
)
return resposta.json().get("transaction")
class Aviso(BaseHTTPRequestHandler):
def do_POST(self):
tamanho = int(self.headers.get("Content-Length", 0))
corpo = self.rfile.read(tamanho)
self.send_response(200) # responda rápido, com 2xx
self.send_header("Content-Length", "0")
self.end_headers()
try:
aviso = json.loads(corpo or b"{}")
except ValueError:
return
id_transacao = aviso.get("idTransaction") if isinstance(aviso, dict) else None
if not isinstance(id_transacao, str):
return
t = confirmar(id_transacao)
if t and t["type"] == "cash_in" and t["status"] == "PAID_OUT":
# Aqui: libere o pedido UMA vez por idTransaction,
# conferindo se t["amount"] é o valor que você esperava.
print("Pix confirmado:", t["idTransaction"], t["amount"])
HTTPServer(("0.0.0.0", 3000), Aviso).serve_forever()API de Pix
Cobranças (Pix recebido) e transferências (Pix enviado). Toda cobrança nasce com o status WAITING_FOR_APPROVAL e passa para PAID_OUT quando é paga.
Gerar cobrança #
/wallet/deposit/paymentCria uma cobrança Pix e devolve o código copia e cola e a imagem do QR code. Quando o pagamento é confirmado, o valor líquido entra no saldo da carteira e a URL de postback é avisada.
Corpo da requisição
| Campo | Descrição |
|---|---|
amountnumberobrigatório | Valor da cobrança em reais, por exemplo 25.00, com até duas casas decimais e no máximo 999999.99. Precisa respeitar o valor mínimo da plataforma. |
debtor_namestringobrigatório | Nome do pagador. |
emailstringobrigatório | E-mail do pagador, em formato válido. |
debtor_document_numberstringopcional | CPF ou CNPJ do pagador. Envie sempre que tiver. |
phonestringobrigatório | Telefone do pagador, com DDD. |
method_paystringobrigatório | Meio de pagamento. Use pix. Para receber em BTC ou USDT, veja Receber em cripto. |
postbackstringobrigatório | URL pública (http ou https) do seu sistema que recebe o aviso de Pix recebido. Endereços internos, localhost e domínios que não resolvem são recusados. |
split_emailstringopcional | E-mail da conta que recebe parte do valor. Veja Cobrança com split. |
split_percentagenumberopcional | Percentual do split, de 0 a 100. |
Resposta 200
| Campo | Descrição |
|---|---|
idTransactionstring | Identificador da cobrança. Guarde: é com ele que você reconhece o aviso e faz as consultas. |
qrcodestring | Código Pix copia e cola. |
qr_code_image_urlstring ou null | Imagem do QR code pronta para exibir. Se não vier, gere o QR code a partir do campo qrcode. |
qr_code_base64string ou null | A mesma imagem em PNG, codificada em base64 e sem o prefixo data:. Para exibir sem depender de outro servidor: <img src="data:image/png;base64,...">. |
A resposta traz também um objeto charge com os mesmos dados. Use os campos acima e ignore o que não conhecer.
Erros desta rota
| HTTP | Motivo |
|---|---|
| 422 | Campo obrigatório faltando, e-mail inválido, valor com mais de duas casas decimais, percentual de split fora de 0 a 100, ou postback que não é uma URL pública. O corpo traz errors com o campo e o motivo. |
| 401 | Valor abaixo do mínimo de depósito da plataforma. A mensagem informa o mínimo. |
| 500 | O processador do pagamento não gerou o QR code, ou a plataforma está sem processador ativo. Tente de novo mais tarde. |
Mais os erros de autenticação e de limite, comuns a todas as rotas.
curl -X POST \
"https://app.cherryfy.co/api/wallet/deposit/payment" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 25.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/deposit/payment');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 25.00,
'debtor_name' => 'Marina Souza',
'email' => '[email protected]',
'debtor_document_number' => '12345678909',
'phone' => '11999999999',
'method_pay' => 'pix',
'postback' => 'https://seusite.com.br/webhooks/pix',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/deposit/payment`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
amount: 25.00,
debtor_name: 'Marina Souza',
email: '[email protected]',
debtor_document_number: '12345678909',
phone: '11999999999',
method_pay: 'pix',
postback: 'https://seusite.com.br/webhooks/pix',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/deposit/payment",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"amount": 25.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"qrcode": "00020126580014br.gov.bcb.pix...6304A1B2",
"qr_code_image_url": "https://exemplo.com/qr/7c1f2b9e.png",
"qr_code_base64": "iVBORw0KGgoAAAANSUhEUgAA..."
}{
"status": "error",
"message": "Erro de validação",
"errors": {
"email": [
"O campo email é obrigatório."
],
"phone": [
"O campo phone é obrigatório."
]
}
}{
"status": "error",
"message": "Nenhum adquirente configurado."
}Cobrança com split #
/wallet/deposit/paymentÉ a mesma rota da cobrança, com dois campos a mais. Quando o Pix é pago, uma parte do valor é repassada automaticamente para outra conta da Cherryfy.
| Campo | Descrição |
|---|---|
split_emailstringopcional | E-mail de cadastro da conta que recebe o repasse. |
split_percentagenumberopcional | Percentual repassado, de 0 a 100. |
Regras
- O split só acontece quando os dois campos são enviados.
- O percentual é aplicado sobre o valor líquido da cobrança, ou seja, depois da taxa da sua conta.
- O repasse é feito na confirmação do pagamento: o valor líquido entra no seu saldo e a parte do split sai para a conta de destino em seguida.
- O e-mail precisa ser de uma conta existente na Cherryfy. Se não for, o repasse não acontece e o valor fica inteiro com você.
- O aviso de Pix recebido traz
split_processed,split_amountesplit_recipient.
A vitrine de afiliação do painel usa este mesmo mecanismo para pagar a comissão do afiliado.
curl -X POST \
"https://app.cherryfy.co/api/wallet/deposit/payment" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 100.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix",
"split_email": "[email protected]",
"split_percentage": 10
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/deposit/payment');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 100.00,
'debtor_name' => 'Marina Souza',
'email' => '[email protected]',
'debtor_document_number' => '12345678909',
'phone' => '11999999999',
'method_pay' => 'pix',
'postback' => 'https://seusite.com.br/webhooks/pix',
'split_email' => '[email protected]',
'split_percentage' => 10,
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/deposit/payment`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
amount: 100.00,
debtor_name: 'Marina Souza',
email: '[email protected]',
debtor_document_number: '12345678909',
phone: '11999999999',
method_pay: 'pix',
postback: 'https://seusite.com.br/webhooks/pix',
split_email: '[email protected]',
split_percentage: 10,
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/deposit/payment",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"amount": 100.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "pix",
"postback": "https://seusite.com.br/webhooks/pix",
"split_email": "[email protected]",
"split_percentage": 10,
},
timeout=30,
)
print(resposta.status_code, resposta.json())Consultar status #
/statusConsulta simples, que devolve só o status de uma cobrança. Não pede credencial: foi pensada para a tela de pagamento acompanhar o QR code.
Corpo da requisição
| Campo | Descrição |
|---|---|
idTransactionstringobrigatório | O identificador devolvido na criação da cobrança. |
Resposta 200
| Campo | Descrição |
|---|---|
statusstring | Um dos status de cobrança, ou NOT_FOUND quando o identificador não existe. Atenção: NOT_FOUND também volta com HTTP 200. |
- Só enxerga cobranças. Para saques, use a consulta da transação.
- O teto é de 20 chamadas por minuto, por IP. Em uma tela de pagamento, consulte a cada 5 segundos ou mais. Se a consulta sair do seu servidor, o teto vale para todos os seus clientes juntos: nesse caso, espere o aviso.
- Para decidir a liberação de um pedido no servidor, prefira a consulta autenticada, que também devolve o valor.
curl -X POST \
"https://app.cherryfy.co/api/status" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/status');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'idTransaction' => '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/status`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
idTransaction: '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/status",
headers={
"Accept": "application/json",
},
json={
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"status": "WAITING_FOR_APPROVAL"
}{
"status": "PAID_OUT"
}{
"status": "NOT_FOUND"
}Transferir / sacar #
/pixoutEnvia um Pix do saldo da carteira para uma chave Pix. Pela API o pedido vai para o processador na hora, sem passar pela fila de aprovação do painel. É a rota mais sensível da API e tem três exigências:
- Credencial válida de uma conta ativa.
- IP de origem permitido, cadastrado em Perfil › Segurança › IPs permitidos. Aceita IP único (
203.0.113.10), faixa CIDR (203.0.113.0/24) ou curinga (203.0.113.*). - Saldo para cobrir o valor mais a taxa de saque da sua conta.
Corpo da requisição
| Campo | Descrição |
|---|---|
amountnumberobrigatório | Valor a enviar, em reais. O beneficiário recebe esse valor; a taxa de saque é debitada do saldo à parte. |
pixKeystringobrigatório | Chave Pix de destino. |
pixKeyTypestringobrigatório | Tipo da chave: cpf, cnpj, email, telefone (ou phone) ou aleatoria. |
baasPostbackUrlstringobrigatório | URL pública (http ou https) do seu sistema que recebe o aviso do saque. O valor web não é aceito. |
external_idstringopcional | Identificador do pedido no seu sistema, até 64 caracteres (letras, números, ponto, traço, sublinhado e dois-pontos). Repetir a chamada com o mesmo external_id devolve o saque já criado em vez de pagar de novo. Envie sempre. |
Resposta 200
| Campo | Descrição |
|---|---|
idstring | Identificador do saque. É o idTransaction usado no aviso e na consulta da transação. |
external_idstring ou null | O external_id que você enviou. |
amountnumber | Valor solicitado. |
pixKeystring | Chave de destino. CPF, CNPJ e telefone podem voltar só com os dígitos. |
pixKeyTypestring | Tipo da chave, em maiúsculas e no padrão do processador: CPF, CNPJ, EMAIL, PHONE ou EVP (aleatória). |
withdrawStatusIdstring | PendingProcessing: enviado ao processador, aguardando a confirmação. Paid: concluído. Failed: recusado, valor devolvido. PendingApproval: só em saques pedidos pelo painel. Trate qualquer outro valor como pedido em andamento. |
createdAtstring | Criação do pedido, em ISO 8601 (UTC). |
updatedAtstring | Última atualização, em ISO 8601 (UTC). |
idempotenteboolean | Só aparece, com true, quando a resposta é de um saque já existente, devolvido porque o external_id se repetiu. |
Um 200 significa que o pedido foi registrado e enviado, não que o dinheiro chegou. Considere o saque aceito somente quando a resposta trouxer id, e espere o status final pelo aviso ou pela consulta da transação.
Erros desta rota
| HTTP | Motivo |
|---|---|
| 403 | IP de origem fora da lista de permitidos. O corpo traz client_ip, o IP que o servidor enxergou: é esse que deve ser cadastrado. |
| 403 | baasPostbackUrl com o valor web, reservado ao painel. |
| 401 | Saldo insuficiente para o valor mais a taxa, ou valor abaixo do saque mínimo da plataforma. |
| 422 | Campo obrigatório faltando, pixKeyType fora da lista, external_id fora do formato ou baasPostbackUrl que não é uma URL pública. |
| 500 | O processador recusou ou não respondeu. Repita com o mesmo external_id: se o saque chegou a ser registrado, ele volta em vez de ser pago de novo. |
Se a sua chamada terminar em erro de rede ou tempo esgotado, o saque pode ter sido registrado mesmo assim. Repita com o mesmo external_id: a resposta devolve o saque existente (com idempotente igual a true) ou cria um novo se nada tinha sido registrado. Sem external_id, confira o saldo em GET /wallet/balance e o relatório de saídas do painel antes de enviar de novo.
curl -X POST \
"https://app.cherryfy.co/api/pixout" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 50.00,
"pixKey": "12345678909",
"pixKeyType": "cpf",
"baasPostbackUrl": "https://seusite.com.br/webhooks/saque",
"external_id": "pedido-8841"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/pixout');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 50.00,
'pixKey' => '12345678909',
'pixKeyType' => 'cpf',
'baasPostbackUrl' => 'https://seusite.com.br/webhooks/saque',
'external_id' => 'pedido-8841',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/pixout`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
amount: 50.00,
pixKey: '12345678909',
pixKeyType: 'cpf',
baasPostbackUrl: 'https://seusite.com.br/webhooks/saque',
external_id: 'pedido-8841',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/pixout",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"amount": 50.00,
"pixKey": "12345678909",
"pixKeyType": "cpf",
"baasPostbackUrl": "https://seusite.com.br/webhooks/saque",
"external_id": "pedido-8841",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"id": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"external_id": "pedido-8841",
"amount": 50,
"pixKey": "12345678909",
"pixKeyType": "CPF",
"withdrawStatusId": "PendingProcessing",
"createdAt": "2026-09-30T15:00:00.000000Z",
"updatedAt": "2026-09-30T15:00:00.000000Z"
}{
"id": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"external_id": "pedido-8841",
"amount": 50,
"pixKey": "12345678909",
"pixKeyType": "CPF",
"withdrawStatusId": "PendingProcessing",
"createdAt": "2026-09-30T15:00:00.000000Z",
"updatedAt": "2026-09-30T15:00:00.000000Z",
"idempotente": true
}{
"success": false,
"message": "IP não autorizado para realizar saques",
"client_ip": "203.0.113.10"
}{
"status": "error",
"message": "Saque pelo painel exige sessão e PIN. Pela API, informe a URL de postback do seu sistema."
}{
"status": "error",
"message": "Saldo Insuficiente."
}API de Cripto
Receber em cripto #
/wallet/deposit/paymentMesma rota da cobrança Pix, com method_pay igual a crypto. Você informa o valor em reais e a moeda; a resposta traz o endereço de carteira e a quantia exata em cripto que o pagador precisa enviar. Quando a rede confirma, o processador converte para reais e o valor líquido entra na carteira, com o mesmo aviso de pagamento recebido.
Disponível para contas cujo processador tem cripto habilitado. Nas demais, a rota responde 422 sem criar nada.
Corpo da requisição
| Campo | Descrição |
|---|---|
amountnumberobrigatório | Valor em reais que você quer receber, por exemplo 100.00. A quantia em cripto é calculada pelo processador na cotação do momento. |
method_paystringobrigatório | Use crypto. |
currencystringobrigatório | Moeda que o pagador vai enviar: BTC ou USDT. |
debtor_namestringobrigatório | Nome do pagador. |
emailstringobrigatório | E-mail do pagador. |
phonestringobrigatório | Telefone do pagador, com DDD. |
debtor_document_numberstringopcional | CPF ou CNPJ do pagador, se tiver. |
postbackstringobrigatório | URL pública (http ou https) do seu sistema que recebe o aviso quando o valor cair. |
Resposta 200
| Campo | Descrição |
|---|---|
idTransactionstring | Identificador da cobrança, o mesmo que volta no aviso e nas consultas. |
walletAddressstring | Endereço de carteira que o pagador deve usar. Vale só para esta cobrança. |
cryptoAmountstring | Quantia exata em cripto a enviar. Mostre ao pagador junto com o endereço; valores diferentes podem não ser reconhecidos. |
currencystring | Moeda, como enviada: BTC ou USDT. |
networkstring | Rede informada pelo processador para o envio. |
amountnumber | Valor em reais pedido na cobrança. |
qr_code_image_urlstring | QR code do endereço, pronto para exibir. |
A cotação muda até a confirmação na rede: o valor creditado é o que o processador converteu de fato, e é ele que vem no campo amount do aviso. Não trate a cobrança como paga antes do aviso.
Erros desta rota
| HTTP | Motivo |
|---|---|
| 422 | Moeda fora de BTC/USDT, campo obrigatório faltando, ou conta sem processador com cripto. |
| 401 | Valor abaixo do mínimo de depósito da plataforma. |
| 500 | O processador não gerou o endereço. Tente de novo mais tarde. |
curl -X POST \
"https://app.cherryfy.co/api/wallet/deposit/payment" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 100.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "crypto",
"currency": "USDT",
"postback": "https://seusite.com.br/webhooks/pix"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/deposit/payment');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 100.00,
'debtor_name' => 'Marina Souza',
'email' => '[email protected]',
'debtor_document_number' => '12345678909',
'phone' => '11999999999',
'method_pay' => 'crypto',
'currency' => 'USDT',
'postback' => 'https://seusite.com.br/webhooks/pix',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/deposit/payment`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
amount: 100.00,
debtor_name: 'Marina Souza',
email: '[email protected]',
debtor_document_number: '12345678909',
phone: '11999999999',
method_pay: 'crypto',
currency: 'USDT',
postback: 'https://seusite.com.br/webhooks/pix',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/deposit/payment",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"amount": 100.00,
"debtor_name": "Marina Souza",
"email": "[email protected]",
"debtor_document_number": "12345678909",
"phone": "11999999999",
"method_pay": "crypto",
"currency": "USDT",
"postback": "https://seusite.com.br/webhooks/pix",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"idTransaction": "8d2f0c1e-4b7a-4e0d-9c3a-2f6b1d5e7a90",
"method": "crypto",
"currency": "USDT",
"network": "USDT",
"walletAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"cryptoAmount": "18.42000000",
"amount": 100,
"qrcode": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"qr_code_image_url": "https://exemplo.com/qr/8d2f0c1e.png",
"message": "Envie exatamente 18.42000000 USDT (rede USDT) para o endereço. O crédito em reais cai após a confirmação na rede."
}{
"status": "error",
"message": "Depósito em cripto não está disponível na adquirente desta conta."
}{
"status": "error",
"message": "Nenhum adquirente configurado."
}Saque em cripto #
O saque em cripto existe para contas em plataformas com um processador de saída em cripto habilitado. Quando está disponível, a opção aparece no painel, em Carteira › Saque.
Você escolhe a rede e a moeda entre as opções oferecidas pelo processador naquele momento, informa o endereço da carteira de destino e confirma com o PIN de 6 dígitos. O pedido fica pendente até a aprovação da plataforma.
Não disponível. POST /pixout trabalha somente com chaves Pix: um pedido com pixKeyType igual a crypto é recusado com 422 e nada é debitado. Para receber em cripto, use Receber em cripto.
As redes e moedas não são fixas: a lista vem do processador e só aparece para contas habilitadas. Por isso esta documentação não promete nenhuma rede ou moeda específica.
API de Carteira
Consultas somente de leitura. Tudo é filtrado pela conta dona da credencial: uma credencial nunca enxerga saldo nem transação de outra conta.
Consultar saldo #
/wallet/balanceDevolve o saldo da carteira da conta. Não tem parâmetros.
Resposta 200
| Campo | Descrição |
|---|---|
statusstring | Sempre success. |
currencystring | Moeda do saldo. Sempre BRL. |
balance.availablenumber | Saldo disponível para saque. |
balance.pending_withdrawalsnumber | Soma dos saques que ainda estão pendentes. |
balance.blockednumber | Valor bloqueado pela plataforma. Normalmente 0. |
updated_atstring | Momento da consulta, em ISO 8601 com fuso horário. |
curl "https://app.cherryfy.co/api/wallet/balance" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Accept: application/json"<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Accept: application/json',
],
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/balance`, {
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
Accept: 'application/json',
},
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.get(
f"{BASE}/wallet/balance",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"status": "success",
"currency": "BRL",
"balance": {
"available": 1520.75,
"pending_withdrawals": 50,
"blocked": 0
},
"updated_at": "2026-09-30T12:00:00-03:00"
}{
"status": "error",
"message": "Token ou Secret inválidos"
}Consultar transação #
/wallet/transactionDevolve os dados de uma transação da sua conta, seja uma cobrança (cash_in) ou um saque (cash_out). É a fonte de verdade para confirmar um aviso.
Corpo da requisição
| Campo | Descrição |
|---|---|
idTransactionstringobrigatório | O idTransaction da cobrança ou o id do saque. Também aceita o valor de externalreference. |
Resposta 200
| Campo | Descrição |
|---|---|
transaction.typestring | cash_in para cobrança, cash_out para saque. |
transaction.idTransactionstring | Identificador da transação. |
transaction.externalreferencestring | Referência da transação no processador. |
transaction.methodstring | Meio usado. Normalmente pix. |
transaction.statusstring | Situação atual. Veja Status das transações. |
transaction.amountnumber | Valor bruto. |
transaction.net_amountnumber | Na cobrança, o valor que entra no saldo. No saque, o valor enviado ao beneficiário. |
transaction.feenumber | Taxa cobrada da conta nesta transação. |
transaction.payerobject | Só em cash_in: name e document do pagador. |
transaction.beneficiaryobject | Só em cash_out: name, document, pix_key e pix_key_type. |
transaction.end_to_endstring ou null | Só em cash_out: identificador da transferência, quando informado. |
transaction.created_atstring | Criação, em ISO 8601 com fuso horário. |
transaction.updated_atstring | Última atualização, em ISO 8601 com fuso horário. |
Erros desta rota
| HTTP | Motivo |
|---|---|
| 422 | O idTransaction não foi enviado. |
| 404 | Não existe transação com esse identificador nesta conta. É a mesma resposta para um identificador de outra conta. |
curl -X POST \
"https://app.cherryfy.co/api/wallet/transaction" \
-H "X-Api-Token: seu_token" \
-H "X-Api-Secret: seu_secret" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17"
}'<?php
$base = 'https://app.cherryfy.co/api';
$ch = curl_init($base . '/wallet/transaction');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-Api-Token: ' . getenv('CHERRYFY_TOKEN'),
'X-Api-Secret: ' . getenv('CHERRYFY_SECRET'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'idTransaction' => '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
]),
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r([$http, $resposta]);const BASE = 'https://app.cherryfy.co/api';
const resposta = await fetch(`${BASE}/wallet/transaction`, {
method: 'POST',
headers: {
'X-Api-Token': process.env.CHERRYFY_TOKEN,
'X-Api-Secret': process.env.CHERRYFY_SECRET,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
idTransaction: '7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17',
}),
});
const dados = await resposta.json();
console.log(resposta.status, dados);import os
import requests
BASE = "https://app.cherryfy.co/api"
resposta = requests.post(
f"{BASE}/wallet/transaction",
headers={
"X-Api-Token": os.environ["CHERRYFY_TOKEN"],
"X-Api-Secret": os.environ["CHERRYFY_SECRET"],
"Accept": "application/json",
},
json={
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
},
timeout=30,
)
print(resposta.status_code, resposta.json()){
"status": "success",
"transaction": {
"type": "cash_in",
"idTransaction": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"externalreference": "7c1f2b9e-5a3d-4e8f-9b21-3f6a0d4c8e17",
"method": "pix",
"status": "PAID_OUT",
"amount": 25,
"net_amount": 23.75,
"fee": 1.25,
"payer": {
"name": "Marina Souza",
"document": "12345678909"
},
"created_at": "2026-09-30T11:58:03-03:00",
"updated_at": "2026-09-30T12:00:41-03:00"
}
}{
"status": "success",
"transaction": {
"type": "cash_out",
"idTransaction": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"externalreference": "b4d2a6f0-1c7e-4f3a-8a55-9e0c2d7b6f41",
"method": "pix",
"status": "PENDING",
"amount": 50,
"net_amount": 50,
"fee": 1.5,
"beneficiary": {
"name": "Sua Empresa LTDA",
"document": "12345678909",
"pix_key": "12345678909",
"pix_key_type": "CPF"
},
"end_to_end": null,
"created_at": "2026-09-30T12:00:00-03:00",
"updated_at": "2026-09-30T12:00:00-03:00"
}
}{
"status": "error",
"message": "Informe o idTransaction da transação."
}{
"status": "error",
"message": "Transação não encontrada nesta conta."
}Status das transações #
Os valores abaixo aparecem no campo status da consulta de status e da consulta da transação.
Cobranças (cash_in)
| Status | Significado | O que fazer |
|---|---|---|
WAITING_FOR_APPROVAL | Cobrança criada, aguardando o pagamento. | Aguardar. |
PAID_OUT | Paga. O valor líquido entrou no saldo. | Liberar o pedido. |
CANCELLED | Cancelada ou não paga. | Não liberar. Gere outra cobrança, se for o caso. |
REFUNDED | Estornada depois de paga. O valor saiu do saldo. | Desfazer a liberação. |
MEDIATION | Em mediação. O valor sai do saldo disponível até a decisão. | Acompanhar pelo painel. |
Saques (cash_out)
| Status | Significado | O que fazer |
|---|---|---|
PENDING | Pedido registrado: enviado ao processador (API) ou aguardando aprovação (painel). | Aguardar o aviso ou consultar de novo. |
PAID_OUT | Pix enviado. Registros antigos podem aparecer como COMPLETED. | Dar o saque como concluído. |
REJECTED | Não enviado. O valor voltou para o saldo. Registros antigos podem aparecer como CANCELLED. | Conferir a chave Pix e pedir de novo. |
PENDING_APPROVAL | Só em registros antigos. Hoje o saque do painel que espera aprovação aparece como PENDING. | Aguardar. |
Trate qualquer valor que você não conheça como "ainda não concluído" e não libere nada com base nele.
Checklist de produção #
Antes de colocar a integração no ar, confira cada item. As marcações ficam salvas só neste navegador.