PIX Cash-In -- Gerar QR Code
Gera uma cobrança PIX com QR Code para recebimento de valores na conta associada à sua API Key.
Endpoint
POST /api/external/pix/cash-inHeaders
| Header | Tipo | Obrigatório | Descrição |
|---|---|---|---|
Authorization | String | Sim | ApiKey {client_id}:{client_secret} |
Content-Type | String | Sim | application/json |
hmac | String | Sim | Assinatura HMAC-SHA512 do body (saiba mais) |
Idempotency-Key | String | Não | Chave única para evitar processamento duplicado (max 256 chars) |
X-Key-Case | String | Não | Defina como camelCase para receber os campos da resposta em camelCase (padrão é snake_case) |
Request Body
| Campo | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
amount | Integer | Sim | Valor em centavos (R$ 30,00 = 3000) | 3000 |
description | String | Não | Descrição da cobrança. Se omitido, o padrão é "Cobranca PIX". | "Pedido #1234" |
external_id | String | Não | Identificador do seu sistema para rastreamento. Max 128 chars. Apenas a-zA-Z0-9._:- (valores fora do padrão são silenciosamente descartados e o campo volta como null -- veja aviso abaixo). Retornado em respostas e webhooks. | "order-9876" |
pix_key | String | Não | Chave PIX específica para gerar o QR Code. Se omitida, usa a chave ativa mais recente da conta (ordem por inserted_at DESC). | "12345678901" |
city | String | Não | Cidade do recebedor no QR Code. Padrão: SAO PAULO. Truncada automaticamente para 15 caracteres. | "RIO DE JANEIRO" |
Envie amount SEMPRE como inteiro (em centavos)
O campo amount DEVE ser um inteiro em centavos. NUNCA envie valores float/decimal:
- ✅
"amount": 3000→ R$ 30,00 - ❌
"amount": 30.00→ interpretado como30centavos = R$ 0,30 (cobrança 100× menor do que pretendido) - ❌
"amount": 30→ R$ 0,30 (também incorreto)
Em JavaScript, converta sempre com Math.round antes de enviar:
const valorEmReais = 30.0;
const amount = Math.round(valorEmReais * 100); // 3000Em Python: amount = round(valor_em_reais * 100). Em Go: amount := int(math.Round(valorEmReais * 100)).
Valores monetários (entrada × resposta)
Valores de entrada são em centavos (R$ 1,00 = 100). Valores de resposta são em unidades base (R$ 1,00 = 10000). Para converter a resposta para reais, divida por 10.000. Nunca use ponto flutuante em nenhum sentido.
external_id inválido = descarte silencioso
Se o external_id contiver caracteres fora de a-zA-Z0-9._:-, ultrapassar 128 bytes, ou for apenas espaços em branco, o servidor descarta silenciosamente o valor e a resposta volta com "external_id": null (nenhum erro é retornado). Sempre confira o external_id presente na resposta antes de usá-lo para conciliação -- se veio null, seu identificador foi rejeitado pela validação.
Exemplo
BODY='{"amount":3000,"description":"Pedido #1234","external_id":"order-9876"}'
HMAC=$(echo -n "$BODY" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | awk '{print $2}')
curl -X POST https://api.owem.com.br/api/external/pix/cash-in \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "hmac: $HMAC" \
-d "$BODY"Resposta de Sucesso (200)
{
"worked": true,
"transaction_id": "7popu57v6us7p6pcicgq12345",
"qr_code": "00020126580014br.gov.bcb.pix...",
"qr_code_image": "data:image/png;base64,iVBORw0KGgo...",
"external_id": "order-9876",
"amount": 300000,
"status": "active",
"type": "dynamic",
"location_url": "https://qrcode.owem.com.br/pix/v2/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"expires_at": "2026-03-07T16:30:00Z"
}| Campo | Tipo | Descrição |
|---|---|---|
worked | Boolean | true indica sucesso na operação |
transaction_id | String | null | Identificador único da cobrança (tx_id do QR Code, alfanumérico máx. 35 chars per spec BACEN). null apenas em falhas internas raras de persistência |
qr_code | String | null | Código EMV copia-e-cola para pagamento. null (valor JSON literal, não a string "null") apenas em falhas internas raras de persistência |
qr_code_image | String | Imagem do QR Code codificada em base64 (PNG, prefixo data:image/png;base64,). String vazia ("") em falhas internas raras |
external_id | String | null | Seu identificador, retornado tal como enviado. null se não informado, se inválido (ver aviso acima), ou se descartado pela sanitização |
amount | Integer | Valor da cobrança em unidades base (÷ 10.000 para reais). 300000 = R$ 30,00 |
status | String | Status inicial sempre active (QR Code ativo para pagamento). A evolução posterior (paid/expired/cancelled) é visível em consultas e webhooks (veja ciclo de vida do QR) |
type | String | null | Tipo do QR Code: dynamic (padrão desde abril/2026) ou static. Dinâmico requer que o banco do pagador consulte location_url e valide o JWS |
location_url | String | null | URL de consulta do payload dinâmico do BACEN (ex: https://qrcode.owem.com.br/pix/v2/{uuid}). Não é o JWS em si -- o banco do pagador faz um GET neste endpoint para receber o payload ISO 20022 assinado (JWS PS256). Presente apenas em QR dinâmico; null em estático |
expires_at | String | null | Data/hora de expiração do QR Code em ISO 8601 UTC com sufixo Z (ex: 2026-03-07T16:30:00Z). null se QR sem expiração |
QR dinâmico é o padrão
Todas as contas em produção usam QR dinâmico por padrão desde abril/2026. O QR dinâmico inclui uma URL (location_url) que o banco do pagador consulta para obter o payload assinado via JWS -- compatibilidade maximizada com bancos BACEN-strict.
Resposta de Erro (400)
{
"worked": false,
"detail": "O campo amount é obrigatório"
}Resposta de Erro (401)
{
"error": {
"status": 401,
"message": "Missing API key credentials. Use Authorization: ApiKey <client_id>:<client_secret>"
}
}Resposta de Erro (422)
{
"worked": false,
"detail": "Invalid HMAC signature"
}Fluxo Recomendado
- Gere a cobrança com este endpoint
- Exiba o QR Code (
qr_code_image) ou o código copia-e-cola (qr_code) ao pagador - Receba a confirmação via Webhook quando o pagamento for efetuado
- Ou consulte o status: por ID, por E2E, por Tag
Validade do QR Code
O QR Code gerado tem validade de 1 hora por padrão. A validade é configurável por conta (campo qrcode_expiration_seconds); verifique sempre o expires_at retornado na resposta para a data/hora exata.
Após o vencimento, o status muda para expired automaticamente (via worker interno, rotina a cada 5 minutos). Para cobranças canceladas manualmente pelo merchant, o status é cancelled. Veja a lista completa de status em Consultar Cash-In por ID.
Ciclo de Vida do QR Code
O QR Code passa por estes estados após a criação:
| Estado | Origem | Descrição |
|---|---|---|
active | Inicial | QR gerado com sucesso, pronto para ser escaneado/pago |
paid | Pagamento recebido | Pagamento BACEN confirmado e linkado ao QR (via worker interno após ACCC) |
expired | Worker QrExpirationChecker | TTL atingiu expires_at. Worker roda a cada 5 min marcando QRs active expirados e disparando webhook pix.charge.expired |
cancelled | Manual ou em massa | Cancelado pelo merchant (via portal) ou em operações administrativas (ex: migração estático→dinâmico em abril/2026 cancelou QRs estáticos ativos com valor) |
used | Legado | Estado intermediário transitório do pipeline antigo. Clientes novos devem tratar como equivalente a paid |
Em consultas, paid pode aparecer como settled
Os endpoints GET /transactions/:id e equivalentes retornam o campo status do ponto de vista da transação (não do QR). Um QR pago aparece como status: "settled" na consulta, com type: "pix" (ou type: "pix_qrcode" em janela curta pós-settlement enquanto a linha final em transactions ainda é persistida). Veja Consultar Cash-In por ID para a tabela completa.