Protocolo de Gateway Guava v1

Especificação para gateways e subadquirentes integrarem com a Guava. Implemente os endpoints abaixo e qualquer lojista poderá conectar seu gateway em Gateways → Gateway compatível Guava, informando URL base e chaves.

O dinheiro nunca passa pela Guava: as cobranças são criadas na conta do lojista no seu gateway, com as credenciais que ele mesmo cadastra. A Guava orquestra o checkout, o roteamento entre gateways e a retentativa automática.

Visão geral

O lojista cadastra: baseUrl, secretKey, webhookSecret e, para cartão, publicKey + tokenizeUrl. Toda chamada servidor→servidor usaAuthorization: Bearer {secretKey} e, nas criações, Idempotency-Key. Valores em centavos.

CampoTipoDescrição
GET /v1/healthobrigatórioValida credenciais (botão “Testar conexão”). Responda 200.
POST /v1/chargesobrigatórioCria cobrança PIX ou cartão.
GET /v1/charges/{id}obrigatórioConsulta status (usado como confirmação autoritativa após webhooks).
POST /v1/charges/{id}/refundsrecomendadoEstorno total ou parcial.
POST {tokenizeUrl}cartãoTokenização no navegador (CORS liberado). O PAN nunca toca a Guava.

Criar cobrança

POST {baseUrl}/v1/charges

Authorization: Bearer sk_xxx
Idempotency-Key: pix_ord_8Kd2xQ
Content-Type: application/json

{
  "method": "pix",                    // "pix" | "card"
  "amount": 30780,                    // centavos
  "currency": "BRL",
  "reference": "ord_8Kd2xQ",          // ID do pedido na Guava (devolva nos webhooks)
  "description": "Método Foco Total + 1 adicional",
  "customer": { "name": "Maria Silva", "email": "maria@email.com", "document": "52998224725", "phone": "11987654321" },
  "notification_url": "https://app.guava.com.br/api/webhooks/gateways/{accountId}",
  "expires_in": 1800,                 // PIX: segundos
  "installments": 3,                  // cartão
  "card_token": "tok_abc123",         // cartão: token gerado pelo seu tokenizeUrl
  "metadata": { "utm_source": "instagram" }
}

200 OK · resposta

{
  "id": "ch_123",
  "status": "pending",                // pending | paid | authorized | refused | failed | expired | refunded | chargeback | canceled
  "pix": { "copy_paste": "00020126…6304ABCD", "qr_code_image": "data:image/png;base64,… ou https://…", "expires_at": "2026-10-06T12:30:00Z" },
  "card": { "brand": "visa", "last4": "1111" },
  "decline": { "code": "insufficient_funds", "category": "soft", "message": "Saldo insuficiente" }
}

Categorias de recusa (cartão)

A categoria decide se a Guava tenta o gateway de fallback do lojista:

CampoTipoDescrição
softretentávelSaldo insuficiente, timeout, erro do emissor. Dispara fallback e oferta de PIX.
harddefinitivaCartão bloqueado/cancelado. Não tenta outro gateway.
frauddefinitivaSuspeita de fraude. Nunca retenta.
invalid_datadefinitivaDados do cartão inválidos.

Para recusas, responda HTTP 200 (ou 402) com status: "refused" e o objeto decline. Use 4xx/5xx apenas para erros de requisição/indisponibilidade.

Tokenização de cartão (navegador)

POST {tokenizeUrl} (chamado pelo checkout, CORS *)

{ "public_key": "pk_xxx", "number": "4111111111111111", "holder_name": "MARIA SILVA", "exp_month": 12, "exp_year": 2030, "cvv": "123" }

→ 200 { "token": "tok_abc123" }

O checkout tokeniza em paralelo no gateway principal e no de fallback do lojista, por isso o token deve valer por pelo menos 10 minutos. Para o upsell de 1 clique, aceite reutilizar o mesmo token por até 30 minutos.

Webhooks para a Guava

Envie um POST para notification_url a cada mudança de status. Assine com o webhookSecret do lojista:

POST {notification_url}

X-Guava-Timestamp: 1791246602
X-Guava-Signature: t=1791246602,v1=<hex>
Content-Type: application/json

{ "id": "evt_987", "type": "charge.updated", "data": { "id": "ch_123", "status": "paid", "reference": "ord_8Kd2xQ" } }

// v1 = HMAC_SHA256(webhookSecret, "<timestamp>.<corpo cru>")

A Guava valida a assinatura (tolerância de 5 minutos), registra o evento por id (idempotência) e confirma o status chamando GET /v1/charges/{id} antes de liberar o pedido. Responda 2xx em até 10 segundos; reenvie em caso de falha.

Estorno

POST {baseUrl}/v1/charges/{id}/refunds

Idempotency-Key: refund_ch_123_30780
{ "amount": 30780 }

→ 200 { "id": "rf_1", "status": "refunded" }   // ou "pending"

Homologação

Para ser listado como gateway nativo no painel (com logo e campos próprios), envie à equipe Guava: URL de sandbox, credenciais de teste e exemplos de webhook. Gateways com API própria também podem ser integrados nativamente — a ZuckPay é o primeiro exemplo.