Skip to content

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-in

Headers

HeaderTipoObrigatórioDescrição
AuthorizationStringSimApiKey {client_id}:{client_secret}
Content-TypeStringSimapplication/json
hmacStringSimAssinatura HMAC-SHA512 do body (saiba mais)
Idempotency-KeyStringNãoChave única para evitar processamento duplicado (max 256 chars)
X-Key-CaseStringNãoDefina como camelCase para receber os campos da resposta em camelCase (padrão é snake_case)

Request Body

CampoTipoObrigatórioDescriçãoExemplo
amountIntegerSimValor em centavos (R$ 30,00 = 3000)3000
descriptionStringNãoDescrição da cobrança. Se omitido, o padrão é "Cobranca PIX"."Pedido #1234"
external_idStringNãoIdentificador 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_keyStringNãoChave PIX específica para gerar o QR Code. Se omitida, usa a chave ativa mais recente da conta (ordem por inserted_at DESC)."12345678901"
cityStringNãoCidade 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 como 30 centavos = 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:

js
const valorEmReais = 30.0;
const amount = Math.round(valorEmReais * 100); // 3000

Em 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

bash
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)

json
{
  "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"
}
CampoTipoDescrição
workedBooleantrue indica sucesso na operação
transaction_idString | nullIdentificador ú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_codeString | nullCó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_imageStringImagem do QR Code codificada em base64 (PNG, prefixo data:image/png;base64,). String vazia ("") em falhas internas raras
external_idString | nullSeu identificador, retornado tal como enviado. null se não informado, se inválido (ver aviso acima), ou se descartado pela sanitização
amountIntegerValor da cobrança em unidades base (÷ 10.000 para reais). 300000 = R$ 30,00
statusStringStatus 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)
typeString | nullTipo 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_urlString | nullURL 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_atString | nullData/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)

json
{
  "worked": false,
  "detail": "O campo amount é obrigatório"
}

Resposta de Erro (401)

json
{
  "error": {
    "status": 401,
    "message": "Missing API key credentials. Use Authorization: ApiKey <client_id>:<client_secret>"
  }
}

Resposta de Erro (422)

json
{
  "worked": false,
  "detail": "Invalid HMAC signature"
}

Fluxo Recomendado

  1. Gere a cobrança com este endpoint
  2. Exiba o QR Code (qr_code_image) ou o código copia-e-cola (qr_code) ao pagador
  3. Receba a confirmação via Webhook quando o pagamento for efetuado
  4. 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:

EstadoOrigemDescrição
activeInicialQR gerado com sucesso, pronto para ser escaneado/pago
paidPagamento recebidoPagamento BACEN confirmado e linkado ao QR (via worker interno após ACCC)
expiredWorker QrExpirationCheckerTTL atingiu expires_at. Worker roda a cada 5 min marcando QRs active expirados e disparando webhook pix.charge.expired
cancelledManual ou em massaCancelado 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)
usedLegadoEstado 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.

Owem Pay Instituição de Pagamento — ISPB 37839059