Guia de integração
Para o time de tecnologia do estabelecimento. Em 10 minutos você cria uma cobrança, o comprador paga na página da NEO, e o seu sistema é avisado por webhook.
Ambientes
| Ambiente | Base da API | Checkout | Chave | Observação |
|---|---|---|---|---|
| Sandbox | https://sandbox.hubbpay.tech/v1 | pay-sandbox.hubbpay.tech | neo_test_… | loja de homologação da Fiserv; cartões de teste; Pix simulado (confirma sozinho); sem dinheiro real |
| Produção | https://hub.hubbpay.tech/v1 | pay.hubbpay.tech | neo_live_… | emitida pela NEO depois do roteiro de homologação |
checkout_url e redireciona o comprador. Na página da NEO, o cartão vai do navegador direto ao cofre da adquirente. Isso mantém o seu sistema fora do escopo PCI de dados de cartão.Autenticação
Toda chamada leva a chave do estabelecimento no cabeçalho Authorization: Bearer <chave>. A chave identifica o estabelecimento — o corpo nunca diz "quem sou eu". Ela é mostrada uma única vez quando a NEO a emite; se perder, a NEO gera outra (a anterior é revogada na hora). Guarde-a como segredo de servidor: nunca em app, site ou repositório.
curl https://sandbox.hubbpay.tech/v1/cobrancas?limite=5 \
-H "Authorization: Bearer neo_test_..."
Limite: 120 chamadas por minuto por chave (429 acima disso). Chave inválida ou revogada: 401.
Idempotência
Todo POST exige o cabeçalho Idempotency-Key (até 128 caracteres; um UUID por operação é o ideal). Repetir a chamada com a mesma chave e o mesmo corpo devolve a mesma resposta, com Idempotent-Replayed: true — reenviar depois de um timeout é seguro. A mesma chave com corpo diferente responde 409. Além disso, a referencia (id do pedido no seu sistema) é única por estabelecimento: repetir uma referência responde 409 com o id da cobrança existente.
Cobrança com cartão
POST /v1/cobrancas
Authorization: Bearer neo_test_...
Idempotency-Key: 6b1d2c8e-5f0a-4c1e-9d3b-7a8e2f4c6d10
Content-Type: application/json
{
"valor_cents": 45000,
"meio": "cartao",
"parcelas": 3,
"referencia": "PED-10931",
"descricao": "Pedido 10931 — Loja Exemplo",
"cliente": { "nome": "Maria Silva", "email": "maria@exemplo.com" },
"return_url": "https://loja.exemplo.com.br/retorno"
}
HTTP/1.1 201 Created
{
"id": "4gwfx-35ERAB",
"status": "aguardando",
"meio": "cartao",
"valor_cents": 45000,
"parcelas": 3,
"referencia": "PED-10931",
"checkout_url": "https://pay-sandbox.hubbpay.tech/l/4gwfx-35ERAB",
"expira_em": "2026-11-11T13:32:12.156Z",
"eventos": [ { "em": "2026-11-10T13:32:12.167Z", "evento": "criada" } ]
}
Redirecione o comprador para checkout_url. Quando ele pagar, você recebe cobranca.aprovada no webhook (ou consulta o GET), e o comprador volta para a sua return_url com ?cobranca=<id>&status=aprovada&referencia=PED-10931. O status na URL é informativo; a verdade é o webhook ou o GET.
| Campo | Obrigatório | Regra |
|---|---|---|
valor_cents | sim | inteiro em centavos, mínimo 100 |
meio | não | cartao (padrão) ou pix |
parcelas | não | 1 a 12, sem juros, no limite do plano do estabelecimento; só cartão |
referencia | sim | 1–64 caracteres (letras, números, . _ - : /); única por estabelecimento |
descricao | não | até 120 caracteres; aparece no checkout |
cliente | não | {nome, documento, email}; pré-preenche o checkout |
return_url | não | https; recebe cobranca, status e referencia na query |
expira_em | não | ISO-8601; padrão 24 h (cartão) / 30 min (Pix); máximo 30 dias |
captura | não | true (padrão). false = pré-autorização — ainda não disponível |
Cobrança com Pix
POST /v1/cobrancas
{ "valor_cents": 8990, "meio": "pix", "referencia": "PED-10930" }
HTTP/1.1 201 Created
{
"id": "hEHpDRLM2kYu", "status": "aguardando", "meio": "pix", "valor_cents": 8990,
"referencia": "PED-10930",
"pix": { "copia_cola": "00020126580014br.gov.bcb.pix…", "expira_em": "2026-11-10T14:02:12.282Z" },
"eventos": [ { "evento": "criada" }, { "evento": "pix_gerado" } ]
}
Mostre o copia_cola ao comprador e desenhe o QR a partir dele (qualquer biblioteca de QR Code; é o padrão EMV do Banco Central). Quando o Pix liquidar, você recebe cobranca.paga e o GET passa a paga com o nsu. O Pix expira em 30 minutos por padrão.
Status da cobrança
| status | Significa | Final? |
|---|---|---|
aguardando | criada; o comprador ainda não pagou (cartão: checkout aberto ou não; Pix: QR gerado) | não |
pendente | cartão enviado à adquirente e ainda sem resposta; a NEO está consultando | não |
aprovada / paga | cartão autorizado / Pix liquidado | sim |
negada | o emissor recusou; o comprador pode tentar outro cartão no mesmo checkout_url | não |
erro | a adquirente falhou; o checkout_url continua válido | não |
expirada | passou de expira_em sem pagamento | sim |
cancelada | cancelada antes do pagamento, ou estornada | sim |
em_analise | a adquirente não respondeu três vezes; a NEO confere manualmente antes de liberar | não |
Consulta e listagem
GET /v1/cobrancas/{id}
GET /v1/cobrancas?de=2026-11-01&ate=2026-11-10&status=aprovada&limite=50
A consulta devolve a cobrança com bandeira, cartao_final (4 últimos), autorizacao, nsu e a lista de eventos. Nunca devolve mais nada do cartão.
Cancelamento e estorno
POST /v1/cobrancas/{id}/cancelamento
Idempotency-Key: ...
{}
Cobrança não paga: deixa de ser pagável (status cancelada). Cobrança paga: estorno total na adquirente — cartão ou Pix — e status cancelada. Não há estorno parcial. Já estornada: 409.
Webhooks
Cadastre uma URL https pública; a NEO manda um POST assinado a cada mudança de estado. O segredo é devolvido uma vez.
POST /v1/webhooks
Idempotency-Key: ...
{ "url": "https://loja.exemplo.com.br/neo/webhook" }
HTTP/1.1 201 Created
{ "id": "…", "url": "…", "eventos": ["*"], "segredo": "whsec_…" }
O que chega
POST https://loja.exemplo.com.br/neo/webhook
Content-Type: application/json
X-Neo-Event: cobranca.aprovada
X-Neo-Delivery: 3f1c… (id único da entrega — ignore repetidos)
X-Neo-Timestamp: 1794263400 (segundos unix)
X-Neo-Signature: sha256=… (HMAC-SHA256 do segredo sobre timestamp + "." + corpo)
{
"evento": "cobranca.aprovada",
"id": "4gwfx-35ERAB", "referencia": "PED-10931", "status": "aprovada",
"meio": "cartao", "valor_cents": 45000, "parcelas": 3,
"ocorrido_em": "2026-11-10T13:33:18.187Z",
"pagamento": { "bandeira": "mastercard", "cartao_final": "8589", "autorizacao": "AG0729", "nsu": "2611…" }
}
Conferindo a assinatura (Node.js)
const crypto = require("crypto");
function webhookValido(headers, corpoCru, segredo) {
const ts = headers["x-neo-timestamp"], sig = headers["x-neo-signature"] || "";
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // janela de 5 min
const esperada = "sha256=" + crypto.createHmac("sha256", segredo).update(ts + "." + corpoCru).digest("hex");
return esperada.length === sig.length && crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(sig));
}
Use o corpo cru da requisição (antes de qualquer parse). Responda 2xx em até 10 segundos e processe depois. Sem 2xx, a NEO tenta de novo em 1 min, 5 min, 30 min, 2 h e 12 h; depois a entrega fica como "desistiu" e pode ser reenviada por POST /v1/webhooks/entregas/{id}/reenviar ou pela NEO.
| Evento | Quando |
|---|---|
cobranca.aprovada | cartão autorizado |
cobranca.paga | Pix liquidado |
cobranca.negada | emissor recusou (o link segue pagável) |
cobranca.erro | adquirente falhou (o link segue pagável) |
cobranca.cancelada | cancelamento antes do pagamento ou estorno |
cobranca.expirada | venceu sem pagamento |
ping | POST /v1/webhooks/teste |
Auditoria: GET /v1/webhooks/entregas?cobranca=<id> lista tentativas, código HTTP e resposta do seu servidor.
Erros
| HTTP | Quando |
|---|---|
| 400 | corpo inválido — a mensagem diz o campo ({"erro": "valor_cents deve ser inteiro em centavos, mínimo 100"}) |
| 401 | chave ausente, inválida ou revogada |
| 403 | a chave não tem o escopo (cobrança, consulta, estorno) ou o estabelecimento está inativo |
| 404 | cobrança inexistente ou de outro estabelecimento |
| 409 | Idempotency-Key reutilizada com outro corpo; referencia repetida (traz o id); estorno já feito |
| 422 | cadastro do estabelecimento incompleto na adquirente (lista faltando) — fale com a NEO |
| 429 | limite de 120 chamadas/min por chave |
| 502 | a adquirente não aceitou (Pix não gerado, estorno recusado) — a mensagem traz o motivo |
Homologação e produção
No sandbox, use os cartões de teste fornecidos pela NEO; o Pix confirma sozinho. Para receber a chave de produção, a integração passa pelo roteiro de homologação da NEO: cobrança aprovada, negada, parcelada, cancelamento antes do pagamento, estorno de cobrança paga, Pix pago e estornado, expiração, e webhook recebido com assinatura conferida. Evidências: os ids das cobranças e as entregas de webhook.
Dúvidas: fale com o seu contato na NEO Pagamentos.