Conceitos
Conceitos fundamentais para integrar com a API da Owem Pay.
Arquitetura de Segurança
A API utiliza três camadas de proteção independentes. Todas são obrigatórias.
Camada 1 -- API Key + Secret
Cada integrador recebe um par de credenciais (client_id e client_secret). O secret nunca é armazenado em texto puro -- guardamos apenas o hash. Quando uma requisição chega, o secret enviado é comparado com o hash armazenado. Se não corresponder, a requisição é rejeitada imediatamente, antes de chegar à lógica de negócio.
Camada 2 -- Assinatura HMAC-SHA512 por Requisição
Além da API Key, cada requisição transacional (POST) precisa enviar uma assinatura HMAC-SHA512 no header hmac.
O processo funciona assim:
- O integrador serializa o body da requisição como JSON
- Gera o hash HMAC-SHA512 usando o
client_secretcomo chave - Envia o hash em hexadecimal no header
hmac
Do nosso lado, recalculamos o hash com o mesmo método e comparamos com o valor recebido. Se qualquer byte do conteúdo for alterado no caminho (por exemplo, em um ataque man-in-the-middle), a assinatura não vai bater e a requisição é rejeitada com erro 401. Essa comparação é feita em tempo constante (constant-time comparison), o que evita ataques de timing que tentam descobrir a assinatura byte a byte.
Camada 3 -- Whitelist de IP Obrigatória
Cada API Key só pode ser usada a partir de IPs previamente autorizados. Mesmo que alguém tenha acesso às credenciais, não conseguirá usar a API a partir de outro IP. Requisições de IPs não autorizados recebem 403 Forbidden.
Proteções Adicionais
| Proteção | Descrição |
|---|---|
| Rate Limiting | 90.000 requisições/minuto por IP (autenticado). Endpoints de autenticação: 5 req/min |
| Cloud Armor (WAF) | Firewall de aplicação protegendo o cluster GKE |
| HTTPS obrigatório | TLS 1.2 ou superior em todas as conexões |
| HSTS | HTTP Strict Transport Security habilitado |
Detalhes completos: Autenticação | HMAC-SHA512
Por que HMAC e não mTLS?
O mTLS (mutual TLS) adiciona autenticação via certificado X.509 no nível da conexão. É uma camada válida, mas no nosso cenário o HMAC por requisição oferece proteção equivalente ou mais adequada:
| Aspecto | mTLS | HMAC-SHA512 |
|---|---|---|
| O que valida | A conexão (canal TLS) | Cada requisição individualmente |
| Integridade do payload | Não -- se a conexão é confiável, requisições passam | Sim -- qualquer alteração no body rejeita a requisição |
| Gestão operacional | Complexa: emissão, rotação, revogação, CRL/OCSP | Simples: gera novo par, atualiza, invalida anterior |
| Incidentes comuns | Certificados expirados ou mal gerenciados | Raros -- chave é string, sem ciclo de vida complexo |
O TLS já garante criptografia do transporte. O HMAC entra como camada adicional, garantindo integridade e autenticidade do payload -- algo que o mTLS por si só não cobre.
Valores Monetários
A API Owem Pay usa duas unidades diferentes dependendo da direção:
| Direção | Unidade | Escala | Exemplo R$ 30,00 |
|---|---|---|---|
| Requisição enviada (request body) | centavos | BRL x 100 | 3000 |
| Resposta recebida (response body) | unidades base | BRL x 10.000 | 300000 |
Conversão rápida
- Para enviar: multiplique o valor em reais por 100. R$ 30,00 =
3000 - Para ler respostas: divida por 10.000.
300000/ 10.000 = R$ 30,00 - Nunca use ponto flutuante -- sempre inteiros
Tabela de referência
| Valor BRL | Request (centavos) | Response (unidades base) |
|---|---|---|
| R$ 1,00 | 100 | 10000 |
| R$ 30,00 | 3000 | 300000 |
| R$ 150,50 | 15050 | 1505000 |
| R$ 1.000,00 | 100000 | 10000000 |
Atenção
O valor 3000 na requisição (R$ 30,00) vira 300000 na resposta. São o mesmo valor em BRL, representado em unidades diferentes. Se você dividir a resposta por 100 em vez de 10.000, obterá R$ 3.000,00 em vez de R$ 30,00.
External ID
O campo external_id é um identificador opcional que você define no seu sistema para rastrear transações. Ele é aceito nos endpoints de cash-in e cash-out e devolvido em todas as respostas e webhooks associados.
| Atributo | Valor |
|---|---|
| Obrigatório | Não |
| Tamanho máximo | 128 caracteres |
| Caracteres permitidos | Alfanuméricos, ., _, :, - |
| Regex | ^[a-zA-Z0-9._:\-]+$ |
| Exemplo | "order-9876", "invoice-4521", "ref:2026-03-07:001" |
Além de ser retornado nas respostas, você pode consultar uma transação pelo external_id:
GET /api/external/transactions/ref/{external_id}Rastreamento
Use o external_id para correlacionar transações da Owem Pay com pedidos, faturas ou registros do seu sistema. Valores duplicados não são rejeitados, mas recomendamos unicidade para facilitar a conciliação.
Idempotência
Requisições de escrita (POST) aceitam o header Idempotency-Key para evitar processamento duplicado. Se a mesma chave for enviada em uma segunda requisição idêntica dentro de 24 horas, a API retorna a resposta original cacheada em vez de processar novamente.
Idempotency-Key: unique-request-id-123| Atributo | Valor |
|---|---|
| Header | Idempotency-Key |
| Tamanho máximo | 256 caracteres |
| TTL do cache | 24 horas |
| Aplica-se a | Apenas POST (cash-in, cash-out, refund, webhooks, CPF) |
| Resposta replay | Header X-Idempotent-Replay: true |
Importante
A chave de idempotência considera método + path + chave. Duas requisições para endpoints diferentes com a mesma chave são tratadas como operações distintas.
Status de Transação
Owem usa um vocabulário único entre POST responses, GET responses e webhook bodies — o mesmo valor aparece em todas as superfícies. Veja PIX Lifecycle para o mapa completo.
Cash In (Recebimentos)
| Status | Onde aparece | Descrição |
|---|---|---|
active | POST /pix/cash-in response | QR Code recém-gerado |
created | Webhook pix.charge.created body | QR Code criado |
paid | Webhook pix.charge.paid body | Terminal. PIX recebido e creditado |
settled | GET /transactions/:id response | Terminal. Mesmo que paid — transação já em transactions |
pending | GET quando QR ainda não foi pago | QR ativo, aguardando pagamento |
expired | GET quando QR expirou | QR não foi pago dentro do TTL |
cancelled | GET quando QR foi cancelado | Cobrança cancelada pelo merchant |
Cash Out (Envios)
| Status | Onde aparece | Descrição |
|---|---|---|
accepted | POST /pix/cash-out response (HTTP 202) | Intermediário — aceito para processamento assíncrono |
processing | Webhook pix.payout.processing + GET enquanto em voo | Intermediário — enviado ao SPI, aguardando BACEN |
settled | Webhook pix.payout.confirmed + GET quando liquidado + POST response (HTTP 200 fast-track) | Terminal de sucesso. Débito confirmado pelo SPI/BACEN |
rejected | Webhook pix.payout.failed body | Terminal de falha. Rejeitado pelo SPI, hold liberado |
failed | GET /transactions/:id quando falhou | Terminal de falha. Mesmo que rejected, mas aparece no GET |
returned | Webhook pix.payout.returned body | PIX enviado devolvido após liquidação (total ou parcial) |
Regra de ouro para conciliação
Só trate como final quando receber pix.payout.confirmed (status settled) ou pix.payout.failed (status rejected). accepted e processing são intermediários.
End-to-End ID (E2E ID)
Identificador único de uma transação PIX no ecossistema do Banco Central. Formato padrão:
E{ISPB}{YYYYMMDDHHMM}{sequencial}Exemplo: E37839059202603071530000001
| Componente | Valor | Descrição |
|---|---|---|
E | Prefixo fixo | Identifica como E2E ID |
37839059 | ISPB da Owem Pay | 8 dígitos |
202603071530 | Data e hora UTC | AAAAMMDDHHMM (12 dígitos) |
000001 | Sequencial | 6 dígitos |
O E2E ID é gerado automaticamente pela Owem Pay e retornado na resposta de cada operação PIX. Use-o para rastrear transações entre instituições.
Tipos de Chave PIX
| Tipo | Formato | Exemplo | Limite PF | Limite PJ |
|---|---|---|---|---|
cpf | 11 dígitos | 12345678901 | 1 | -- |
cnpj | 14 dígitos | 12345678000190 | -- | 1 |
email | E-mail válido | contato@empresa.com.br | 5 | 20 |
phone | DDD + número (11 dígitos) | 11999998888 | 5 | 20 |
evp | UUID v4 (chave aleatória) | a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d | 5 | 20 |
Padrão de Resposta
Todas as respostas da API seguem o padrão:
Sucesso
{
"worked": true,
...
}Erro
{
"worked": false,
"detail": "Descrição do erro"
}O campo worked indica se a operação foi bem-sucedida (true) ou falhou (false). Em caso de erro, o campo detail descreve o motivo.