Skip to Content
Referência da APIAutenticação

Autenticação

A InfraIO Pay tem duas superfícies de API com modelos de autenticação diferentes. Escolha a que combina com quem está chamando:

SuperfíciePrefixo do pathAudiênciaAuth
B2B do lojista/b2b/v1/*Seu servidorAssinatura de requisição HMAC-SHA256
DashboardPor serviço: /auth/*, /payment/*, /merchant/*, /event/*, /user/*, …Sessões de navegador para o dashboard do lojistaBearer JWT

Esta página cobre a superfície B2B — a que você chama do seu servidor com um par de chaves de API. Se você está embutindo o dashboard InfraIO ou construindo ferramentas internas, use a superfície do dashboard (docs separadas, ainda não públicas).

O gateway roteia cada superfície por um prefixo inicial que remove antes de encaminhar: /b2b/v1/checkout-sessions/quick chega ao payment-service como /v1/checkout-sessions/quick, e o /payment/v1/orders do dashboard chega como /v1/orders. Então se você vê paths /v1/* puros em outros lugares, esse é o path backend-interno depois do prefixo público ter sido removido — o seu cliente sempre envia a forma com prefixo. (Uma consequência para a assinatura: a string canônica B2B assina o path com o prefixo /b2b ainda anexado — veja abaixo.)

Endpoints

AmbienteBase URL
Testehttps://api-dev.infraio.xyz
Livehttps://api.infraio.xyz

Mesmo padrão de URL — o ambiente é controlado pelo prefixo da chave (pk_test_… vs pk_live_…), não pela URL.

Par de chaves

Você pega dois valores no dashboard do lojista (Developers → API keys → + Add key):

  • Chave publicável (pk_test_… ou pk_live_…) — identifica a sua conta. Enviada como X-Client-ID. Seguro embutir no seu bundle do navegador (o SDK já faz isso).
  • Chave secreta (sk_test_… ou sk_live_…) — a chave de assinatura HMAC. Só servidor. Trate como uma senha de banco de dados.

Se uma chave secreta cair num bundle de navegador, repo git, linha de log ou chat compartilhado — revogue imediatamente no dashboard. Não há janela de sobreposição; a revogação é instantânea. Crie uma chave nova e redeploye.

Assinando uma requisição

Toda chamada para /b2b/v1/* leva três headers:

X-Client-ID: pk_live_70d0becbd7a53047b0dfe88a960d10ad X-Timestamp: 1715990400 X-Signature: 9a8b7c6d… (hex HMAC-SHA256)

A assinatura é calculada sobre uma string canônica:

METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY
  • METHOD — verbo HTTP em maiúsculas (POST, GET, …).
  • PATH — path da requisição incluindo o prefixo /b2b, sem o host e sem a query string (por exemplo, /b2b/v1/checkout-sessions/quick). O gateway verifica a assinatura sobre o path bruto de entrada antes de remover /b2b, então o prefixo precisa estar presente. Parâmetros de query não são assinados — para um GET …?cursor=…&limit=20, assine só o path, não a parte ?….
  • TIMESTAMP — unix segundos, como string decimal (por exemplo, "1715990400"), batendo exatamente com o X-Timestamp.
  • BODY — bytes brutos do body da requisição. String vazia para GET/DELETE.

Assine com HMAC-SHA256 chaveado pela chave secreta, saída hex:

import { createHmac } from "node:crypto"; function sign({ method, path, body, secret }: { method: string; path: string; body: string; secret: string; }) { const timestamp = Math.floor(Date.now() / 1000).toString(); const input = [method.toUpperCase(), path, timestamp, body].join("\n"); const signature = createHmac("sha256", secret).update(input).digest("hex"); return { timestamp, signature }; }

Por que HMAC, e não Bearer?

Uma API de token Bearer puro envia o seu único segredo pela rede em toda requisição. Quem capturar um log de proxy com terminação TLS ganha as chaves da sua conta. Assinar com HMAC significa que o segredo nunca viaja — só a assinatura derivada dele, que é de uso único (vinculada àquela requisição exata + aquele minuto exato).

O trade-off: você tem que computar a assinatura para toda chamada. Um SDK de servidor esconderia isso; até a gente publicar um, o helper acima são ~15 linhas por linguagem.

Tolerância do timestamp

A tolerância obrigatória é de ±5 minutos (300 segundos), aplicada pelo merchant-service quando verifica a assinatura. O próprio gateway é um pouco mais frouxo (310s) como defesa em profundidade, mas uma requisição que passa pelo gateway e falha no check interno ainda termina em 401 invalid_signature — considere 300s como o contrato. Duas implicações:

  1. Sincronize o relógio do seu servidor via NTP. Um cron de longa duração com relógio desviado vai falhar intermitentemente.
  2. Não pré-compute e enfileire assinaturas. Se uma requisição fica numa fila de retry por mais de 5 min, a assinatura expira.

Escopos de chave

Chaves secretas carregam um ou mais destes bundles de escopo:

EscopoUso pretendido
readListar/ler pedidos, sessões, reembolsos
write_orderCriar sessões de checkout, pedidos
write_refundEmitir reembolsos, criar tokens de pedido de reembolso
webhook_manageCriar/atualizar/deletar endpoints de webhook

O dashboard emite uma chave “full access” por padrão (os quatro escopos). Você pode criar uma chave com escopo restrito em Developers → API keys → + Add key e marcar só os escopos que a integração precisa.

A aplicação de escopo é consultiva no momento, não bloqueante. Os escopos são registrados na chave e exibidos de volta para você no dashboard, mas o middleware do gateway ainda não rejeita chamadas fora do escopo — qualquer chave sk_… válida se comporta como full-access hoje. Aplicação de escopo por endpoint está na próxima release. Não confie em escopos como uma fronteira de segurança ainda; trate como rótulos e rotacione / revogue chaves para restringir acesso enquanto isso.

Onde a assinatura é verificada

A validação HMAC acontece uma vez, no gateway. O gateway:

  1. X-Client-ID, X-Timestamp, X-Signature.
  2. Busca o lojista + segredo pelo pk_…, roda o check de janela de timestamp, recomputa a assinatura, compara em tempo constante.
  3. Em sucesso, remove os headers de auth, carimba a requisição com headers internos (X-B2B-Auth: 1, X-Merchant-ID, X-Merchant-Domain) e encaminha para o serviço downstream (payment-service, merchant-service, etc.). Ambiente + escopos resolvidos NÃO são injetados hoje — código downstream que precisa do ambiente o deriva do body da requisição / config por lojista, não dos headers.
  4. Em falha, retorna 401 INVALID_SIGNATURE sem nunca tocar no backend.

Serviços downstream não re-rodam o HMAC — eles confiam nos headers injetados pelo gateway e agem no lojista que o gateway resolveu. Eles não aplicam escopo por endpoint também: como notado acima, o escopo da chave não é injetado, então qualquer sk_… autenticado chega em qualquer endpoint para o seu lojista (aplicação de escopo é consultiva hoje — veja o callout em Escopos de chave). Isso importa de dois jeitos:

  • Se você opera o seu próprio reverse proxy na frente da InfraIO Pay, não remova X-B2B-Auth / X-Merchant-ID (e também não forje — o gateway rejeita requisições de entrada que carreguem esses na borda pública).
  • Os paths de rede pública (/b2b/v1/*) são a única superfície que roda o passo HMAC. gRPC interno entre os nossos serviços usa mTLS — um modelo de confiança diferente que não aceita X-Client-ID.

Próximos passos

  • Erros — formato da resposta em 4xx/5xx.
  • Segurança → Chaves de API — rotação, revogação, o que fazer se um segredo vaza.
  • Webhooks → Verificação de assinatura — usa um esquema HMAC diferente (header X-Signature: sha256=…, assina X-Timestamp + "." + raw_body, mais um X-Signature-Prev opcional durante a janela de tolerância de 24 horas da rotação). Não misture os esquemas — eles compartilham o algoritmo de hash mas os bytes assinados e a família de segredos (whsec_… vs sk_…) são diferentes.