Pedidos BaaS após o login exigem Bearer + três headers de integridade. O próprio POST /api/v2/auth/login e GET /api/v2/baas/status não usam HMAC.
Guia de login: Autenticação da plataforma BaaS · Autenticação da conta BaaS.
| Header | Tipo | Descrição |
|---|
X-Signature | string | HMAC-SHA256 da mensagem canônica (hexadecimal) |
X-Timestamp | integer | Unix timestamp UTC em segundos. Tolerância: ±300 s |
X-Nonce | string | Identificador único por pedido (UUID). Não reutilize em 10 minutos |
METHOD
PATH
QUERY_STRING
BODY
TIMESTAMP
NONCE
| Componente | Regra |
|---|
METHOD | GET, POST, PATCH, DELETE em maiúsculas |
PATH | Caminho com /api/v2, sem barra final (ex.: /api/v2/baas/balances) |
QUERY_STRING | Texto após ?, ou vazio |
BODY | JSON exato em POST/PATCH. Em GET/DELETE assinados: literal [] |
TIMESTAMP | Igual ao header X-Timestamp |
NONCE | Igual ao header X-Nonce |
X-Signature = HMAC-SHA256(mensagem, hmac_secret) em hexadecimal.
const crypto = require("crypto");
function buildSignature({ method, path, query, body, timestamp, nonce, hmacSecret }) {
const bodyStr = method === "GET" || method === "DELETE" ? "[]" : body;
const message = [
method.toUpperCase(),
path,
query || "",
bodyStr,
String(timestamp),
nonce,
].join("\n");
return crypto.createHmac("sha256", hmacSecret).update(message).digest("hex");
}
const timestamp = Math.floor(Date.now() / 1000);
const nonce = crypto.randomUUID();
const requestBody = {
value: 1050,
type_initiation: 1,
idempotency_key: "8eaefc35-96a4-4e33-8f87-751afe81811f",
key: "[email protected]",
name: "Maria Pagadora Exemplo",
ispb: "60701190",
agency: "0001",
account: "1234567",
account_type: 0,
document: "11144477735",
person_type: 0,
};
const signature = buildSignature({
method: "POST",
path: "/api/v2/baas/pix/payments/key",
query: "",
body: JSON.stringify(requestBody),
timestamp,
nonce,
hmacSecret: process.env.HMAC_SECRET,
});
// Headers em todo pedido BaaS assinado:
// Authorization: Bearer {access_token}
// X-Timestamp: {timestamp}
// X-Nonce: {nonce}
// X-Signature: {signature}
| Grupo | Authorization: Bearer | X-Signature / X-Timestamp / X-Nonce | Contexto |
|---|
POST /api/v2/auth/login | não (Basic Auth) | não | , |
GET /api/v2/baas/status | sim (plataforma) | não | Plataforma |
| Onboarding, seller-webhooks, contratos | sim (plataforma) | sim | Plataforma |
| Saldo, Pix, boleto, chaves, webhooks conta | sim (titular) | sim | Conta |
| Situação | Mensagem |
|---|
| Header HMAC ausente | "Missing required HMAC headers" |
X-Timestamp não numérico | "Invalid timestamp format" |
| Relógio fora de ±300 s | "Request timestamp is outside acceptable range" |
| Nonce reutilizado | "Invalid request signature" |
| Assinatura incorreta | "Invalid request signature" |
secret ausente no JWT | "Invalid request signature" |
{
"message": "Missing required HMAC headers"
}
{
"message": "Invalid request signature"
}
{
"message": "Request timestamp is outside acceptable range"
}
| Situação | Body |
|---|
| Token ausente, expirado ou mal formatado | {"message": "Invalid token", "error": ["invalid_credentials"]} |
account_uuid ausente no token | {"message": "Invalid token", "error": ["invalid_credentials"]} |
| Conta não encontrada | {"message": "Account not found", "error": ["invalid_credentials"]} |
| Sintoma | Causa provável |
|---|
401 "Invalid token" no login | client_id ou client_secret incorretos |
403 com login 200 | Scope ausente no scope do login |
401 "Missing required HMAC headers" | X-Signature, X-Timestamp ou X-Nonce omitidos |
401 "Invalid request signature" | hmac_secret errado, body diferente do assinado, path com / final, ou GET com body vazio em vez de [] |
| Token de plataforma em rota de conta | Contexto de credencial errado |