Consulter Cash-Out par ID
Consultez les détails et le status d'une transaction PIX par son transaction_id.
Endpoint
GET /api/external/transactions/:idHeaders
| Header | Type | Obligatoire | Description |
|---|---|---|---|
Authorization | String | Oui | ApiKey {client_id}:{client_secret} |
Path Parameters
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
id | String | Oui | ID de la transaction (transaction_id) |
Exemple
curl -X GET https://api.owem.com.br/api/external/transactions/PIXOUT20260309a1b2c3d4e5f6 \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"La réponse varie selon l'état de la transaction. Cet endpoint cherche dans les sources suivantes, dans l'ordre de priorité :
- Transaction liquidée (
transactionspartransaction_id, ou par l'UUID interne hex —Base.decode16) - PIX OUT en cours (
outbound_requestsstage 1 ou 2) partransaction_id - QR Code (
qrcodespartx_id) — s'il y apaid_at+payment_end_to_end_id, résout la transaction réelle liée danstransactionsvia E2E ; sinon retourne le shape « QR Code Non Payé »
Si rien ne correspond dans aucune source, retourne 404.
Une transaction rejetée N'apparaît PAS ici par transaction_id
Les rejets BACEN synchrones (PACS.002 RJCT) et les force-voids sont persistés dans failed_transactions et ne sont pas trouvés par cet endpoint quand vous consultez par le transaction_id. Utilisez les endpoints alternatifs :
- GET /transactions/e2e/:e2e_id — recherche dans
failed_transactionsparend_to_end_id - GET /transactions/ref/:external_id — recherche dans
failed_transactionsparexternal_id - Webhook
pix.payout.rejected/pix.payout.failed— notification en temps réel avec payload complet
Les rejets de validation d'entrée (400/422 immédiat) ne passent pas par ce flux — ils ont déjà retourné l'erreur synchrone au POST.
Réponse -- Transaction liquidée (200)
{
"worked": true,
"data": {
"id": "c7f3a8b12d4e4f6a9c1b3e5f7a9b1d3e",
"transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
"end_to_end_id": "E37839059202603091530abcdef01",
"external_id": "order-9876",
"type": "pix",
"direction": "outbound",
"status": "settled",
"amount": 300000,
"fee_amount": 350,
"net_amount": 300350,
"description": "Paiement fournisseur",
"counterparty_name": "Joao Silva",
"recipient_key": "12345678901",
"created_at": "2026-03-09T15:30:00Z",
"completed_at": "2026-03-09T15:30:02Z"
}
}| Champ | Type | Description |
|---|---|---|
data.id | String | UUID interne de la transaction en format canonique avec tirets, 36 caractères (ex. : "c7f3a8b1-2d4e-4f6a-9c1b-3e5f7a9b1d3e"). Le controller passe le binaire de 16 octets par Ecto.UUID.load/1 avant de sérialiser — le format N'est PAS hex lowercase de 32 caractères sans tirets |
data.transaction_id | String | Identifiant unique de la transaction (préfixe courant PIXOUT pour les sorties et PIXIN pour les entrées, mais non garanti — lisez toujours le champ, ne dérivez pas du préfixe) |
data.end_to_end_id | String | Identifiant End-to-End dans le SPI/BACEN |
data.external_id | String | Identifiant de votre système. null s'il n'a pas été renseigné |
data.type | String | Type de la transaction. Valeurs courantes : pix, pix_return. Le backend fait passthrough du champ t.type — les rows legacy peuvent retourner d'autres valeurs |
data.direction | String | outbound (cash-out), inbound (cash-in), credit, debit. Les deux derniers apparaissent quand le champ t.direction n'a pas été persisté et le backend a inféré via Helpers.infer_direction/2 à partir de account_id × to_account_id |
data.status | String | Status normalisé (voir tableau ci-dessous) |
data.amount | Integer | Valeur en unités de base (÷ 10 000 pour reais). 300000 = R$ 30,00 |
data.fee_amount | Integer | Frais prélevés en unités de base |
data.net_amount | Integer | Valeur nette en unités de base |
data.description | String | Description renseignée à la création |
data.counterparty_name | String | Nom de la contrepartie (payeur ou bénéficiaire) |
data.recipient_key | String | Clé PIX du destinataire (uniquement pour les sorties) |
data.created_at | String | Date de création (ISO 8601) |
data.completed_at | String | Date de conclusion (ISO 8601), null si en attente |
Réponse -- PIX OUT en cours (200)
Retourné quand la transaction est encore en cours de traitement (avant confirmation BACEN).
{
"worked": true,
"data": {
"status": "processing",
"transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
"end_to_end_id": "E37839059202603091530abcdef01",
"amount": 300000,
"fee_amount": 350,
"net_amount": 300350,
"external_id": "order-9876",
"pix_key": "12345678901",
"description": "Paiement fournisseur",
"type": "pix",
"direction": "outbound",
"payment_status": "processing",
"started_at": "2026-03-09T15:30:00Z",
"recipient": {
"name": "Joao Silva",
"key": "12345678901",
"key_type": "cpf"
}
}
}| Champ additionnel | Type | Description |
|---|---|---|
data.recipient | Object | Données du destinataire résolues via DICT |
data.recipient.name | String | Nom du titulaire de la clé |
data.recipient.key | String | Clé PIX utilisée |
data.recipient.key_type | String | Type de la clé (cpf, cnpj, email, phone, evp) |
data.started_at | String | Date de début du traitement (ISO 8601) |
Réponse -- Transaction rejetée (200)
Retournée par les endpoints /transactions/e2e/:e2e_id et GET /transactions/ref/:external_id quand le PIX a été rejeté par le SPI ou a échoué pendant le traitement. Non retournée par GET /transactions/:id (voir avertissement ci-dessus sur failed_transactions).
{
"worked": true,
"data": {
"status": "failed",
"transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
"end_to_end_id": "E37839059202603091530abcdef01",
"amount": 300000,
"fee_amount": 350,
"external_id": "order-9876",
"type": "pix",
"direction": "outbound",
"payment_status": "failed",
"failure_reason": "rejected: AB03",
"reason_code": "AB03",
"reason_description": "Aborted by PSP of creditor",
"started_at": "2026-03-09T15:30:00Z",
"failed_at": "2026-03-09T15:30:05Z",
"recipient": {
"name": "Joao Silva",
"key": "12345678901"
}
}
}| Champ additionnel | Type | Description |
|---|---|---|
data.failure_reason | String | Motif brut du rejet (format : "rejected: {CODE}" pour les codes BACEN, ou descriptions d'intégration comme "dict_key_not_found", "ambiguous key", "insufficient balance") |
data.reason_code | String | Code structuré extrait de failure_reason. Pour les rejets BACEN, suit ISO 20022 (AC03, AB03, ED05, DUPL etc.). null quand failure_reason ne contient pas de code structuré |
data.reason_description | String | Description humaine du reason_code, en anglais (centralisée dans Fluxiq.UseCases.Pix.ReasonCodes). Exemples : "Invalid creditor account number" (AC03), "Aborted by PSP of creditor" (AB03), "Settlement failed" (ED05). null quand le code n'est pas reconnu |
data.recipient | Object | Données du destinataire (quand disponibles). Peut être omis dans les échecs très précoces |
data.failed_at | String | Date/heure du rejet (ISO 8601) |
Structure des codes de rejet
Les champs reason_code et reason_description sont dérivés du dictionnaire centralisé dans Fluxiq.UseCases.Pix.ReasonCodes. Utilisez-les pour le routage programmatique des erreurs. Gardez failure_reason uniquement pour les logs et le diagnostic. Voir le tableau complet des codes dans PIX Cash-Out par clé -- Codes d'erreur.
Réponse -- QR Code non payé (200)
Retournée quand l'ID correspond à un QR Code qui n'a pas encore été payé.
{
"worked": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transaction_id": "7popu57v6us7p6pcicgq12345",
"end_to_end_id": null,
"external_id": "order-9876",
"type": "pix_qrcode",
"status": "pending",
"amount": 300000,
"fee_amount": 0,
"net_amount": 300000,
"description": "Cobrança PIX",
"direction": "credit",
"counterparty_name": null,
"recipient_key": "12345678901",
"created_at": "2026-03-09T15:30:00Z",
"completed_at": null
}
}| Status QR | Description |
|---|---|
pending | QR Code actif, en attente de paiement |
settled | QR Code avec paid_at renseigné, mais le controller n'a pas pu résoudre la transaction réelle dans transactions par payment_end_to_end_id. Se produit dans la fenêtre entre Phase 1 ACSP (ACK au BACEN) et Phase 2 ACCC (PG MERGE terminé), ou quand le lien QR↔TX échoue pour une autre raison. Chemin de code actif (show_transaction_controller.ex:83) — ne traitez pas comme une erreur ; refaites la consultation quelques secondes plus tard et le backend devrait retourner le shape « Transaction liquidée » normalement |
expired | QR Code expiré (TTL default 60 min — configurable par compte via account.qrcode_expiration_seconds) |
cancelled | QR Code annulé manuellement (ou annulé en masse pendant la migration statique→dynamique en 2026-04) |
Note : quand le QR est payé et que le backend réussit à faire le lookup de la transaction réelle par E2E, la réponse est celle du shape « Transaction liquidée » ci-dessus (avec status: "settled" et le transaction_id réel, pas le tx_id du QR). Ce n'est que quand ce lookup retourne nil que l'on retombe sur le shape « QR Code Non Payé » avec status: "settled".
Valeurs du champ status
Le status du GET dépend de la source
Le GET /transactions/:id cherche dans 4 tables distinctes et retourne un status différent selon la source où la transaction est trouvée. Il n'existe pas de vocabulaire unique entre toutes les sources.
| Status | Source | Signification |
|---|---|---|
processing | outbound_requests (stage 1 ou 2) | PACS.008 envoyée, en attente de confirmation du BACEN. Solde en hold |
processing | outbound_requests (stage 4 — file de retry) | Rate-limited par ClientLimiter / DictBucket.Guard, en attente de retry automatique (Oban PixOutRetryWorker, TTL 120min). Le shape retourné est le même que celui du stage 1/2 — différenciez par le webhook pix.payout.queued déclenché à la mise en file |
settled | transactions (status interne 1) | BACEN a confirmé la liquidation et le solde a déjà été mouvementé. État final de succès |
pending | transactions (status interne 2) | Cas rare — transaction dans un état intermédiaire avant promotion à settled |
failed | transactions (status interne 3) OU failed_transactions | État final d'échec. Rejetée par BACEN (PACS.002 RJCT), orpheline force-voided (>30min en hold), expiration de la file de retry (DICT_QUEUE_TIMEOUT) ou erreur interne |
Note de compatibilité : les rows legacy (antérieures à la consolidation du vocabulaire) peuvent présenter status: "completed" ou status: "accepted". Traitez-les comme équivalents à "settled".
Correspondance avec les webhooks
pix.payout.queuedcorrespond àstatus: "processing"dans le GET tant que la requête est dansoutbound_requests.stage=4pix.payout.confirmedcorrespond toujours àstatus: "settled"dans le GETpix.payout.failedetpix.payout.rejectedcorrespondent toujours àstatus: "failed"dans le GET
Pour les QR Codes (cash-in, hors du scope PIX OUT), la table qrcodes ajoute 4 valeurs : pending, settled, expired, cancelled — décrites dans la section « QR Code non payé » ci-dessus.
Réponse d'erreur -- 404
{
"worked": false,
"detail": "Transação não encontrada"
}