{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"70da2572-6d24-4aec-af19-7556bef5a0a3","name":"HCB API","description":"Coleção de rotas da API para utilização dos serviços HCB.\n\n# Autenticação via Client ID e Client Secret\n\n## Visão Geral\n\nA autenticação por **Client ID** e **Client Secret** é um método seguro de validar requisições API feitas por clientes ou sistemas integradores.  \nEla utiliza um processo de **assinatura digital** (HMAC) para garantir que cada requisição seja:\n\n- Autenticada (prova de identidade do cliente);\n    \n- Íntegra (sem alteração de conteúdo);\n    \n- Não repetida (proteção contra replay attacks).\n    \n\n---\n\n## Fluxo de Validação\n\n1. O cliente possui suas credenciais:\n    \n    - client_id (identificador público)\n        \n    - client_secret (chave privada)\n        \n2. A cada requisição para a API, o cliente deve gerar uma **assinatura (**X-Signature**)** com base nos seguintes dados:\n    \n    - Método HTTP (ex: POST)\n        \n    - Caminho completo da URL (ex: /api/v1/orders)\n        \n    - Hash (SHA256) do corpo da requisição\n        \n    - Timestamp atual (em segundos)\n        \n    - Nonce (valor aleatório único)\n        \n3. Esses valores são concatenados e assinados com o client_secret usando o algoritmo **HMAC-SHA256**.  \n    O resultado é enviado no cabeçalho X-Signature.\n    \n4. O servidor então:\n    \n    - Recupera o client_secret associado ao X-Client-Id;\n        \n    - Recalcula a assinatura internamente;\n        \n    - Compara de forma segura (timing-safe);\n        \n    - Rejeita requisições com:\n        \n        - Timestamp fora da janela de 5 minutos;\n            \n        - Nonce repetido (cache em Redis);\n            \n        - Assinatura inválida.\n            \n\n---\n\n## Cabeçalhos de Autenticação\n\nCada requisição autenticada deve conter os seguintes headers:\n\nHeader Descrição X-Client-Id ID público do cliente (UUID) X-Timestamp Timestamp UNIX (segundos) X-Nonce Valor aleatório único por requisição X-Signature Assinatura digital HMAC-SHA256 gerada com o client_secret\n\n---\n\n## Exemplo de Requisição\n\n```\nPOST /api/v1/orders HTTP/1.1\nHost: api.exemplo.com\nX-Client-Id: 8f1a2e7b-4b3d-4c1c-9b2e-94a3d61a48d3\nX-Timestamp: 1734720000\nX-Nonce: 5e1a3b9e8d7f4c2d\nX-Signature: qnb4lXwItfS6qZk9r1TnC3I4RxvItqNXYeFZn6GxUIw=\nContent-Type: application/json\n{\n  \"amount\": 100,\n  \"currency\": \"USD\"\n}\n\n ```\n\n---\n\n## Verificação no Servidor\n\nO servidor refaz o cálculo:\n\n```\ncanonical_string =\n  METHOD + '\\n' +\n  PATH_WITH_QUERY + '\\n' +\n  BODY_DIGEST + '\\n' +\n  TIMESTAMP + '\\n' +\n  NONCE\n\n ```\n\nEm seguida, gera a assinatura esperada:\n\n```\nsignature = Base64(HMAC_SHA256(canonical_string, client_secret))\n\n ```\n\nSe o resultado for igual à assinatura enviada, a requisição é aceita.\n\n---\n\n## Como usar o script no Postman\n\nO script a seguir automatiza a geração de todos os cabeçalhos de autenticação.\n\n### 1\\. Configurar variáveis\n\nNo Postman, crie variáveis de ambiente:\n\nNome Valor client_id Seu client_id client_secret Seu client_secret. Ou substitua este trecho pelo valor das suas credenciais:\n\n```\nconst clientId = 'seu-client_id';\nconst clientSecret = 'sua-client_secret';\n\n ```\n\n### 2\\. Adicionar o script de pré-requisição\n\nCole o script abaixo no campo **Pre-request Script** da requisição ou da collection:\n\n```\nconst CryptoJS = require('crypto-js');\nconst clientId = pm.variables.get('client_id');\nconst clientSecret = pm.variables.get('client_secret');\nfunction generateNonce() {\n    return CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Hex);\n}\nfunction computeBodyDigest(rawBody) {\n    if(!rawBody) return '';\n    return CryptoJS.SHA256(rawBody).toString(CryptoJS.enc.Base64);\n}\nfunction buildCanonicalString(method, path, bodyDigest, timestamp, nonce) {\n    return [method.toUpperCase(), path, bodyDigest, timestamp, nonce].join('\\n');\n}\nfunction computeSignature(canonical, clientSecret) {\n    const keyHex = clientSecret.replace(/-/g, '').toLowerCase();\n    const key = CryptoJS.enc.Hex.parse(keyHex);\n    return CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(canonical, key));\n}\nconst resolvedPath = pm.variables.replaceIn(pm.request.url.getPathWithQuery());\nconst url = resolvedPath.startsWith('/') ? resolvedPath : '/' + resolvedPath;\nconst timestamp = Math.floor(Date.now() / 1000).toString();\nconst nonce = generateNonce();\nconst rawBody = pm.request.body && pm.request.body.raw ? pm.request.body.raw : '';\nconst bodyDigest = computeBodyDigest(rawBody);\nconst canonical = buildCanonicalString(pm.request.method, url, bodyDigest, timestamp, nonce);\nconst signature = computeSignature(canonical, clientSecret);\npm.request.headers.add({ key: 'X-Client-Id', value: clientId });\npm.request.headers.add({ key: 'X-Timestamp', value: timestamp });\npm.request.headers.add({ key: 'X-Nonce', value: nonce });\npm.request.headers.add({ key: 'X-Signature', value: signature });\n\n ```\n\n### 3\\. Executar a requisição\n\n- O Postman vai gerar automaticamente o nonce, o timestamp e a assinatura.\n    \n- Nenhum desses valores precisa ser preenchido manualmente.\n    \n- O servidor vai validar os cabeçalhos e retornar o resultado conforme o endpoint chamado.\n    \n\n---\n\n## Erros Comuns\n\nCódigo Motivo Solução 401 - Credenciais inválidas client_id não encontrado ou client_secret incorreto Verifique se o par client_id e client_secret está correto 401 - Timestamp fora da janela permitida Diferença de tempo > 5 minutos entre cliente e servidor Ajuste o relógio local 401 - Nonce já utilizado Mesmo nonce usado em outra requisição Gere um novo nonce automaticamente (o script já faz isso) 401 - Assinatura inválida Erro ao gerar a assinatura Verifique se o corpo enviado é idêntico ao corpo assinado\n\n---\n\n## Dica para Testes Locais\n\n- Cada requisição deve ser feita com o corpo **exatamente igual** ao conteúdo assinado (sem espaços ou quebras de linha extras).\n    \n- Use sempre o mesmo ambiente no Postman para manter as variáveis consistentes.\n    \n- O servidor rejeita requisições duplicadas com o mesmo nonce.\n    \n\nEndFragment","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":true,"owner":"26742930","team":8751216,"collectionId":"70da2572-6d24-4aec-af19-7556bef5a0a3","publishedId":"2sB34eKN4G","public":true,"publicUrl":"https://documenter-api.postman.tech/view/26742930/2sB34eKN4G","privateUrl":"https://go.postman.co/documentation/26742930-70da2572-6d24-4aec-af19-7556bef5a0a3","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":""},{"name":"title","value":""}],"appearance":{"default":"dark","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.11.9","publishDate":"2025-07-10T02:16:03.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":""},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[{"name":"New Environment","id":"5b8d972b-5c25-40d6-be71-d62d89b9e627","owner":"26742930","values":[{"key":"apiUrl","value":"https://hcb-api.vercel.app","enabled":true,"type":"default"}],"published":true}],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/073a5fd3f399c3cc03998669337336ecefa22f5d2ae8f3904780ff1da423a6e2","favicon":""},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"},{"label":"New Environment","value":"26742930-5b8d972b-5c25-40d6-be71-d62d89b9e627"}],"canonicalUrl":"https://documenter.gw.postman.com/view/metadata/2sB34eKN4G"}