POC ReufyPay Para Thais (dev) e Luiz (PM) · Gabriel · 2026-05-30
para Luiz para Thais para os dois

Tu não fez
besteira.

A doc Postman da Reufy está incompleta no exemplo de autenticação — o code do exemplo expirou faz tempo. Existe atalho na mesma doc e ele resolve. Só falta a Reufy nos dar credenciais de teste.

para Luiz

01 · Resumo executivo em 60 segundos

TL;DR · A POC está bloqueada por falta de credenciais sandbox da Reufy. Decisão técnica certa, escopo certo. Só falta um email.

O que a gente está construindo

Tela de checkout dentro da Uni4life onde o profissional de saúde preenche dados do cartão de crédito e paga a assinatura — sem ser redirecionado para tela da ReufyPay/Asaas. A Jéssica pediu isso explicitamente: a experiência tem que ficar dentro da Uni4life.

Onde a gente está

O que precisa acontecer agora

  1. Mandar email pro Thales (thales.ribeiro@reufy.com.br) pedindo: email + senha sandbox e confirmar cartão de teste.
  2. Reufy responde com as credenciais.
  3. Thais roda os 3 endpoints no Postman, valida que funciona.
  4. Thais constrói a tela no Bubble usando os mesmos 3 endpoints.
Risco/prazo: sem ação de quem cobra a Reufy, a POC fica parada. Com a credencial em mãos, Thais destrava em ~1 dia útil. Sem credencial, qualquer estimativa é chute.
para os dois

02 · O que aconteceu — narrativa

TL;DR · Thais tentou autenticar usando o exemplo da doc Postman. O exemplo está incompleto. Não é erro dela.

Quarta (28/05) a Reufy mandou um link de doc Postman. A doc tem dois caminhos de autenticação: o OAuth (mais complicado) e o generate_api_token (atalho). A Thais começou pelo OAuth porque é o primeiro item da lista de endpoints.

O exemplo OAuth da doc tem um code hardcoded — algo tipo st_6dc9a57597aa8a65cd1c35970e33d90d. Esse tipo de código é de uso único e expira em segundos. O exemplo da doc tá lá há semanas. Quando a Thais copiou e tentou rodar, o código já tinha expirado faz tempo — daí o erro.

Analogia simples — É como aquele código de 6 dígitos que o banco te manda por SMS. Vale 60 segundos. Se a doc da Reufy mostrasse "olha, esse código que mandei no SMS é 123456", não faria sentido — quando você for ler, já era. O exemplo da doc está nesse formato. Não dá pra reusar.

Soma a isso o fato de que o exemplo também não menciona o parâmetro grant_type=authorization_code, que costuma ser obrigatório nesse tipo de chamada. Conclusão: o exemplo da doc não é runnable como está. Não tem culpa de quem tentou.

para Thais

03 · Por que get_access_token falhou

TL;DR · 3 problemas no exemplo da doc — todos do lado da Reufy. Tu não fez nada de errado.

O endpoint exemplo

POST https://reufy-pay.bubbleapps.io/version-test/api/1.1/oauth/access_token
Content-Type: application/x-www-form-urlencoded

client_id=bbdd1c327fc659700553acb4cc5deae5
client_secret=40dd1ffdba572a95c76bc9360a8889da
redirect_uri=https://reufy-pay.bubbleapps.io/version-test
code=st_6dc9a57597aa8a65cd1c35970e33d90d
📖 Tradução do que esse código está pedindo: "ô servidor da Reufy, sou o app com identidade bbdd1c..., comprovo isso com o segredo 40dd..., e tenho esse comprovante temporário st_6dc9... que o usuário me deu logo agora. Me devolve um Bearer token pra eu usar nas próximas chamadas."

Os 3 problemas

1

O code é descartável (one-shot) e expira em segundos.

Aquele st_6dc9a57... só vale 1 uso e por uns 30-60 segundos depois que o usuário clica "Autorizar" na tela da Reufy. O exemplo da doc tá lá há tempos. Já queimou.

2

Falta o parâmetro grant_type=authorization_code.

Bubble OAuth costuma exigir esse param obrigatório pra distinguir "estou trocando código por token" de "estou renovando token expirado". O exemplo da doc omite, e provavelmente o servidor reclama disso também.

3

Fluxo OAuth completo precisa de browser real.

Pra OAuth funcionar de verdade, o usuário tem que: abrir /oauth/authorize no navegador → fazer login → clicar "Autorizar" → o navegador redireciona pra um URL com ?code=... no final → tu copia esse code FRESQUINHO → manda no POST em até 30 segundos. Tudo isso pra trocar 1 code por 1 token. Trabalhoso pra Postman.

Por isso o Postman sempre retorna erro. Não é setup teu. O exemplo da doc está incompleto pro fluxo real. Vale flaggar com o Thales no mesmo email.
para Thais

04 · O atalho — generate_api_token

TL;DR · Na mesma doc, há um endpoint que troca email+senha por Bearer direto. Uma única chamada. Sem OAuth.
Analogia — Imagina dois jeitos de entrar num site:
(a) Login com Facebook = OAuth. Tu sai do site, vai pro Facebook, autoriza, volta. Vários passos, segurança alta.
(b) Login direto com email/senha = generate_api_token. Manda email + senha, recebe token. 1 passo, mais simples pra testar.
Pra POC, faz o (b). Quando for produção em escala, considera o (a).

A chamada

POST https://app.reufypay.com/version-test/api/1.1/wf/generate_api_token
Content-Type: application/json

{
  "email": "<email_da_subconta_sandbox>",
  "senha": "<senha>"
}
📖 Tradução: "Reufy, sou esse email/senha. Me dá um Bearer token."

O retorno (formato esperado)

{
  "status": "success",
  "response": {
    "token": "abc123def456...",
    "...": "..."
  }
}

Como usar o token nas próximas chamadas

Authorization: Bearer abc123def456...
📖 Tradução: esse header vai em TODAS as chamadas seguintes. É como um crachá que prova "tô autorizado". Sem ele, qualquer chamada retorna 401.
Só falta a credencial. A equipe Reufy precisa criar email + senha sandbox pra Uni4life. Sem isso, esse atalho também não roda — porque tu não tem o que mandar no body. Vai pro item 07 ver como pedir.
para Thais

05 · Fluxo de cartão crédito — 3 calls

TL;DR · Não é call única. São 3, encadeadas. ID de uma alimenta a próxima.

Visão geral

1. criar_cliente

dados paciente
id cus_xxx

2. criar_nova_cobranca

cus_xxx + valor
id pay_xxx

3. pagar_cobranca_cartao

pay_xxx + cartão
status CONFIRMED

Cada call DEPENDE do retorno da anterior. No Bubble, isso vira 3 actions sequenciais; o output de uma alimenta o input da próxima.

Call 1 — criar o cliente

POST /wf/criar_cliente
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Thais Hashimoto",
  "cpfCnpj": "03174766028",
  "email": "thais@uni4life.com.br",
  "mobilePhone": "11994072478",
  "address": "Rua Teste",
  "addressNumber": "702",
  "complement": "bloco 30",
  "province": "Centro",
  "postalCode": "06702155",
  "externalReference": "uni4_user_42"
}
📖 O que essa call FAZ: registra esse paciente no banco de dados da Reufy. Devolve um ID único (cus_xxx) que será usado pra associar a cobrança ao paciente.

Resposta esperada:

{
  "status": "success",
  "response": { "id": "cus_000006039237", "name": "Thais...", "...": "..." }
}

Guarda o id — vai usar na próxima call. Não tem unique_id separado como tu perguntou no vídeo; é só id mesmo.

Call 2 — criar a cobrança

POST /wf/criar_nova_cobranca
Authorization: Bearer <token>

{
  "billingType": "CREDIT_CARD",
  "customer": "cus_000006039237",
  "dueDate": "2026-05-31",
  "value": 100.00,
  "description": "Assinatura mensal Uni4life",
  "externalReference": "order_42",
  "fine":     { "value": 0 },
  "interest": { "value": 0 },
  "discount": { "value": 0 }
}
📖 O que essa call FAZ: registra UMA cobrança de R$100 contra esse cliente, dizendo "vai ser paga com cartão". Devolve um ID de cobrança que tu vai usar na próxima call. Ainda não debitou o cartão de ninguém.
Importante: tu muda billingType de BOLETO (que é o exemplo da doc) pra CREDIT_CARD. Esse parâmetro é o que diz "vai ser cartão", não boleto.

Call 3 — pagar com cartão

POST /wf/pagar_cobranca_cartao
Authorization: Bearer <token>

{
  "idCobranca": "<id da call 2>",
  "creditCard": {
    "holderName": "THAIS HASHIMOTO",
    "number":     "4444 4444 4444 4444",
    "expiryMonth": "08",
    "expiryYear":  "2030",
    "ccv":         "123"
  },
  "creditCardHolderInfo": {
    "name":              "Thais Hashimoto",
    "email":             "thais@uni4life.com.br",
    "cpfCnpj":           "03174766028",
    "postalCode":        "06702155",
    "addressNumber":     "702",
    "addressComplement": "bloco 30",
    "phone":             "1133334444",
    "mobilePhone":       "11994072478"
  }
}
📖 O que essa call FAZ: aí sim. Manda os dados do cartão pro gateway, debita os R$100. Resposta diz CONFIRMED (pagou) ou FAILED (recusou).
Cartões de teste sandbox (padrão)

Cartões de teste universais usados em sandboxes baseadas em Asaas (que é o que a Reufy usa por baixo):

  • 4444 4444 4444 4444 — Visa, geralmente APROVA
  • 5184 1957 8881 1000 — Mastercard, geralmente APROVA
  • Validade: qualquer mês futuro · CCV: 123

Mas o ideal é o Thales confirmar quais cartões funcionam no sandbox dele, junto com cartões que recusam propositalmente (pra a gente testar fluxo de erro).

cURL pra rodar tudo no terminal

Assim que tiver email+senha, podes rodar isso no terminal pra validar antes de mexer no Bubble:

# 1 — pega o token
TOKEN=$(curl -s -X POST https://app.reufypay.com/version-test/api/1.1/wf/generate_api_token \
  -H 'Content-Type: application/json' \
  -d '{"email":"<email>","senha":"<senha>"}' | jq -r '.response.token')

echo "Token: $TOKEN"

# 2 — cria cliente
CLIENTE=$(curl -s -X POST https://app.reufypay.com/version-test/api/1.1/wf/criar_cliente \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Teste","cpfCnpj":"03174766028","email":"t@t.com","mobilePhone":"11999999999"}' | jq -r '.response.id')

echo "Cliente: $CLIENTE"

# 3 — cria cobrança
COBRANCA=$(curl -s -X POST https://app.reufypay.com/version-test/api/1.1/wf/criar_nova_cobranca \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"billingType\":\"CREDIT_CARD\",\"customer\":\"$CLIENTE\",\"dueDate\":\"2026-05-31\",\"value\":100,\"description\":\"teste\",\"externalReference\":\"t1\",\"fine\":{\"value\":0},\"interest\":{\"value\":0},\"discount\":{\"value\":0}}" | jq -r '.response.id')

echo "Cobrança: $COBRANCA"

# 4 — paga
curl -X POST https://app.reufypay.com/version-test/api/1.1/wf/pagar_cobranca_cartao \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"idCobranca\":\"$COBRANCA\",\"creditCard\":{\"holderName\":\"TESTE\",\"number\":\"4444444444444444\",\"expiryMonth\":\"08\",\"expiryYear\":\"2030\",\"ccv\":\"123\"},\"creditCardHolderInfo\":{\"name\":\"Teste\",\"email\":\"t@t.com\",\"cpfCnpj\":\"03174766028\",\"postalCode\":\"06702155\",\"addressNumber\":\"100\",\"addressComplement\":\"\",\"phone\":\"1133334444\",\"mobilePhone\":\"11999999999\"}}"
para os dois

06 · Quais campos a tela de checkout precisa

TL;DR · 10 campos. Tudo que o paciente vai digitar antes de clicar "Pagar".

A tela do checkout dentro da Uni4life precisa coletar exatamente 10 campos antes de bater na sequência de 3 calls. Esses são os campos que a Reufy exige.

CampoDe onde vemUsado na call
Nome completopaciente digita1 e 3
CPFpaciente digita1 e 3
Emailpaciente digita (ou Uni4life já tem)1 e 3
Celularpaciente digita1 e 3
CEP / endereço / número / complementopaciente digita (CEP autocompleta)1 e 3
Número do cartãopaciente digita3
Validade (MM/AAAA)paciente digita3
CCVpaciente digita3
Nome impresso no cartãopaciente digita3
externalReferencebackend Uni4life (ID interno)1 e 2
Atenção segurança (Luiz): a partir do momento que a Uni4life recebe número de cartão + CCV, ela entra no escopo PCI-DSS. Pra POC sandbox tá ok, mas pra produção precisa confirmar com a Reufy se eles oferecem tokenização do cartão (o paciente digita em iframe deles, a Uni4life nunca vê o PAN) — caso contrário, exige certificação. Vale flaggar com o Thales no mesmo email do item 07.
para os dois

07 · Próximo passo bloqueante — email pro Thales

TL;DR · Copia o texto abaixo, manda. Sem isso, a POC fica parada.

Contato: Thales Ribeiro · thales.ribeiro@reufy.com.br · (32) 99915-1340

Sugestão de email (Luiz pode mandar, ou Thais com cópia pro Luiz):

Assunto: ReufyPay sandbox — credenciais para POC Uni4life

Olá, Thales, tudo bem?

Estamos avançando com a POC de checkout cartão de crédito da Uni4life
integrando com a ReufyPay. Lemos a documentação Postman, mapeamos
o fluxo (criar_cliente → criar_nova_cobranca → pagar_cobranca_cartao)
e identificamos 3 pendências para começar os testes:

1. Credenciais sandbox
   Precisamos de uma subconta de teste com email + senha que possamos
   usar no endpoint /wf/generate_api_token para gerar Bearer token.
   (Alternativa: um Bearer token sandbox pré-gerado já serve.)

2. Cartões de teste
   Quais números de cartão funcionam no sandbox para APROVAR a
   transação? E para forçar uma transação RECUSADA, para que
   possamos testar o fluxo de erro?

3. Observação sobre a doc Postman
   O exemplo da seção "OAuth → get_access_token" usa um parâmetro
   "code" que parece estar expirado (códigos de autorização OAuth
   são one-shot). Poderia confirmar se o caminho recomendado para
   integração é o "generate_api_token" via email/senha, ou o fluxo
   OAuth completo? Se for o OAuth, faltaria documentar o passo
   inicial /oauth/authorize e o param grant_type.

Bonus (pode ficar para um segundo momento):
   Existe tokenização de cartão na Reufy para que o frontend da
   Uni4life não precise tocar no PAN diretamente? Isso afeta
   nosso escopo de PCI.

Fico no aguardo, qualquer coisa pode me chamar pelo WhatsApp.

Obrigada,
Thais Hashimoto / Luiz Ribeiro
Uni4life
para Thais

08 · Glossário rápido

TL;DR · Termos que aparecem na doc e no fluxo. Lê quando esbarrar em algum.
Bearer token
Crachá que o servidor te dá após login. Vai em todas as chamadas seguintes no header Authorization: Bearer <token>. Sem ele, qualquer endpoint retorna 401 Unauthorized.
OAuth (authorization_code flow)
Padrão de autenticação onde um app pede permissão pra outro em nome do usuário. Tipicamente: tu envia o usuário pra uma tela de "Autorizar" no provedor, ele autoriza, é redirecionado de volta com um code temporário, e tu troca esse code por um Bearer token. Usado pelo "Login com Google/Facebook".
code (OAuth)
Comprovante temporário (uns 30-60s) que o usuário recebeu depois de autorizar. Tu troca ele por um Bearer permanente. Uso único.
API token (atalho generate_api_token)
Equivalente prático ao Bearer mas obtido com email+senha em uma chamada só. Mais simples pra testar; sem o passo do browser.
Sandbox
Ambiente de teste. URLs com version-test são sandbox; live ou sem version-test é produção. Sandbox aceita cartões fake e não cobra de verdade.
customer / cus_xxxxxxx
ID único do cliente no sistema Reufy. Devolvido por criar_cliente, usado em criar_nova_cobranca.
walletId
ID de uma "carteira" de uma subconta da Reufy. SÓ é usado em split payment (quando uma cobrança é dividida entre múltiplas contas, tipo marketplace). Pra POC simples Uni4life, ignora.
billingType
Tipo de cobrança. Valores possíveis: CREDIT_CARD, BOLETO, PIX. Pra POC: CREDIT_CARD.
externalReference
Campo livre pra tu salvar um ID do TEU sistema (o ID que a Uni4life dá pra ordem de compra). A Reufy não interpreta isso, só guarda. Útil pra cruzar logs depois.
PCI-DSS
Padrão de segurança obrigatório quando teu sistema toca em dados de cartão (número + CCV). Exige auditoria, controles, certificação. Maioria das fintechs oferece "tokenização" pra empurrar essa responsabilidade pra ela e te deixar PCI-free.
tokenização (de cartão)
Em vez de teu sistema receber o número do cartão, o paciente digita num iframe (campo embutido) do gateway. O gateway retorna um TOKEN. Tu manda o token pra Reufy em vez do número. Resultado: teu sistema nunca viu o PAN, tu fica fora do escopo PCI rigoroso.