PIX Cash-Out Copia y Pega
Realiza una transferencia PIX utilizando el codigo EMV (copia y pega) extraido de un QR Code PIX.
Endpoint
POST /api/external/pix/cash-outHeaders
| Header | Tipo | Obligatorio | Descripcion |
|---|---|---|---|
Authorization | String | Si | ApiKey {client_id}:{client_secret} |
Content-Type | String | Si | application/json |
hmac | String | Si | Firma HMAC-SHA512 del body (hex) |
Idempotency-Key | String | No | Clave unica para evitar procesamiento duplicado (max 256 chars). Comportamiento identico al documentado en PIX Cash-Out por Clave |
Permiso obligatorio
La API Key debe tener el permiso transfer:write para enviar PIX. Sin el, la solicitud retorna 403 Forbidden. Vea como configurar permisos.
Request Body
| Campo | Tipo | Obligatorio | Descripcion |
|---|---|---|---|
amount | Integer | Si | Valor en centavos. R$ 30,00 = 3000. En QR dinamico, este valor es sobrescrito por la consulta a la URL del QR — vea abajo |
emv | String | Si | Codigo EMV copia y pega del QR Code PIX. El alias codigo_copia_cola tambien es aceptado pero emv es canonico — prefieralo |
description | String | No | Descripcion de la transferencia (max 140 caracteres) |
external_id | String | No | Identificador de su sistema para rastreo. Max 128 chars despues de trim. Solo caracteres a-zA-Z0-9._:-. Retornado en respuestas y webhooks. Valores invalidos son silenciosamente descartados (transaccion prosigue con external_id: null). Vea PIX Cash-Out por Clave para detalles. |
end_to_end_id | String | No | End-to-End ID en formato BACEN. Recomendado omitir — el backend genera determinista. Solo envie en escenario de reprocesamiento coordinado |
Codigo Copia y Pega
El campo emv acepta el codigo EMV completo copiado de un QR Code PIX. La API extrae automaticamente la clave PIX, los datos del receptor y el valor original del cobro a partir del payload EMV. El backend valida el CRC-16/CCITT-FFFF y la estructura TLV antes de proseguir.
QR Estatico vs QR Dinamico
La API trata los dos tipos de forma distinta:
QR Estatico (PoIM=11, sin URL):
- La clave PIX y los metadatos vienen del propio payload EMV
- El
amountenviado en la solicitud es usado directamente como valor de la transferencia - No hay consulta externa — liquidacion inmediata despues de validacion DICT
QR Dinamico (PoIM=12, con URL en el tag 26/25):
- El backend hace
Provider.consult_qrcodeen la URL embebida en el payload EMV y recibe un JWS (BACEN Manual 2.9.0) - El valor autoritativo viene de la respuesta JWS (
valor.original) y sobrescribe elamountenviado por el cliente - Si la consulta a la URL falla (timeout, JWS invalido, QR expirado en el emisor), retorna HTTP 422 con
detail: "QR Code dinamico nao pode ser resolvido" - Use el valor sobrescrito como fuente de la verdad —
net_amounten la respuesta refleja el valor real cobrado
No confie en el valor enviado en QR dinamico
En QR dinamico, siempre consulte la respuesta del POST para obtener el amount efectivo. El backend ignora cualquier divergencia entre el valor enviado y el valor retornado por el emisor del QR — eso es exigencia BACEN.
Valores monetarios
Los valores de entrada son en centavos (R$ 1,00 = 100). Los valores de respuesta son en unidades base (R$ 1,00 = 10000). Para convertir la respuesta a reales, divida por 10.000. Nunca use punto flotante.
Ejemplo
curl -X POST https://api.owem.com.br/api/external/pix/cash-out \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "hmac: $HMAC" \
-d '{
"amount": 3000,
"emv": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d5204000053039865802BR5913NOME RECEBEDOR6008BRASILIA62070503***6304ABCD",
"description": "Pagamento via QR Code",
"external_id": "invoice-4521"
}'Respuesta de Exito -- 200 / 202
{
"worked": true,
"final": false,
"transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
"end_to_end_id": "E37839059202603091530abcdef01",
"external_id": "invoice-4521",
"amount": 300000,
"fee_amount": 350,
"net_amount": 300350,
"status": "accepted",
"detail": "PIX enviado para processamento"
}HTTP 200 vs 202
- HTTP 200: Transaccion ya liquidada (
final: true,status: "settled"). - HTTP 202: Transaccion aceptada para procesamiento (
final: false).statuspuede ser"accepted"(flujo normal),"queued"(rate-limit DICT — retry automatico cada 3s por hasta 120min, session 155) o"pending_approval"(aguardando aprobacion). Acompane el status via polling o webhook.
| Campo | Tipo | Descripcion |
|---|---|---|
worked | Boolean | true indica que la solicitud fue aceptada |
final | Boolean | true cuando la transaccion alcanzo estado terminal (liquidada o rechazada). false cuando aun en procesamiento |
transaction_id | String | Identificador unico de la transaccion |
end_to_end_id | String | Identificador End-to-End en el SPI/BACEN |
external_id | String | Su identificador, retornado tal como fue enviado. null si no informado |
amount | Integer | Valor de la transferencia en unidades base (÷ 10.000 para reales). 300000 = R$ 30,00. En QR dinamico, refleja el valor autoritativo retornado por la consulta JWS — puede divergir del amount enviado en el request |
fee_amount | Integer | Tarifa cobrada en unidades base (÷ 10.000 para reales) |
net_amount | Integer | Valor bruto debitado en la cuenta pagadora (amount + fee_amount) — no es el valor que el destinatario recibe. Vea la nota en PIX Cash-Out por Clave sobre la asimetria de semantica entre cash-out y cash-in |
status | String | Uno de: accepted, settled, queued, pending_approval. Vea detalles en PIX Cash-Out por Clave |
detail | String | Mensaje descriptivo |
Codigos de Rechazo
Los rechazos del cash-out por EMV siguen exactamente el mismo patron del PIX Cash-Out por Clave — dos formatos de body (Formato A {status: "failed", errors: [...]} y Formato B {errors: {bad_request: "..."}}), tres clases de error (validacion / integracion / rate-limit encolado), y los mismos vocabularios UPPERCASE × lowercase. Los items abajo destacan solo los codigos especificos del camino EMV.
Errores de validacion especificos del EMV (HTTP 400 / 422)
| HTTP | Formato | Campo con codigo | Significado |
|---|---|---|---|
| 400 | B | errors.bad_request: "invalid emv payload" | Payload EMV malformado (CRC-16 invalido, TLV incompleto, tag obligatoria ausente) — detectado por el parser antes del Orchestrator |
| 400 | B | errors.bad_request: "invalid or missing amount" | amount ausente, cero, negativo o no-entero (QR estatico) |
| 422 | A | errors[0].code: "same_institution_transfer" | QR generado por cuenta Owem — PIX intra-institucional no soportado (use TEF). Nota: HTTP 422 (no 400), con shape {status: "failed", errors: [{code: "same_institution_transfer", params: []}]} |
| 422 | — | detail: "QR Code dinamico nao pode ser resolvido" | Falla en la consulta a la URL del QR dinamico (timeout, JWS invalido, QR expirado en el emisor) — este camino es tratado por el controller antes del Orchestrator, retorna shape legacy {errors: {unprocessable_entity: "..."}} |
| 422 | A | errors[0].code: "insufficient_balance" | Saldo disponible menor que amount + fee_amount |
Otros errores
Para los codigos dict_key_not_found, dict_key_blocked, dict_rate_limited (sincronico), dict_bucket_exhausted (sincronico), dict_lookup_failed, provider_rejected, provider_schema_error, provider_unknown_error — todos retornan HTTP 400 en el Formato A (no 429 ni 503). Detalles en PIX Cash-Out por Clave — Errores de integracion.
Rate-limit con retry automatico (HTTP 202 queued)
Cuando el ClientLimiter per-merchant (default DICT_CLIENT_MAX_PER_MIN=120) o el DictBucket.Guard global (refill DICT_BUCKET_REFILL_RATE=18/min, capacity 250) detecta que el limite fue alcanzado antes de llegar al OnZ, el cash-out es encolado en Fluxiq.Workers.PixOutRetryWorker y retorna HTTP 202 con status: "queued". El flag pix_out_retry_queue_enabled esta ON en PRD desde session 155. Detalles completos en PIX Cash-Out por Clave — Rate-limit con retry automatico.
Rechazos BACEN asincronicos
Despues de aceptacion inicial (HTTP 202), el SPI/BACEN puede rechazar via PACS.002 RJCT. Ese rechazo:
- No altera la respuesta HTTP original (ya fue enviada como 202)
- Aparece via
GET /transactions/:idconstatus: "failed"+reason_code(AC03, AB03, ED05 etc.) +reason_descriptionen ingles - Dispara webhook
pix.payout.rejectedcon los mismos campos estructurados
Vea la lista completa de codigos BACEN en Consultar Cash-Out por ID.
Proximos Pasos
Despues de crear la transferencia, acompane el status via:
- Consultar por ID
- Consultar por E2E ID
- Consultar por Tag
- Consultar por External ID --
GET /api/external/transactions/ref/{external_id}
O reciba la confirmacion automaticamente via Webhook.