Create a PIX transaction
Creates an outbound PIX payment. What happens next depends on where the payee is, and the two branches answer with different statuses and different bodies — a client has to handle both.
An on-us payee (payee.ispb equal to this participant’s own ISPB, on a direct order) settles SYNCHRONOUSLY as an INTRA_PSP ledger transfer and answers 201 with the transaction already EXECUTED. The account credited is the one payee.branch, payee.accountNumber and payee.accountDigit name, and it must belong to payee.document (422 PIX-0134). On a payment by key (payee.key) those coordinates are first checked against DICT (§8.2.14, asked as the payer; JDPI answers a key of this institution from its own base): a field the order states differently from the account DICT binds the key to is refused 422 PIX-0033 naming that field (the branch is compared by value, so “1” and “0001” name the same branch, here and in the paying participant’s records), a key DICT does not hold is 404 PIX-1011, and JDPI unavailable is 503 PIX-1050 — all before anything is held. Send the payee object GET /v1/entries//lookup answered and it matches. Any other payee settles over SPI in TWO PHASES: the amount is first HELD on the paying position as a pending ledger debit, and only then is the order submitted to JDPI (§8.4.1), which is asynchronous by design — nothing has settled when the call returns. A direct order answers 201 with the transaction PENDING; an order routed through a registered indirect (indirectId in the body) answers 202 carrying JD’s own §8.4.1 acknowledgement byte-for-byte when JDPI returns one, whose idReqJdPi is the handle the outcome is read with, and 201 PENDING with this plugin’s body when JDPI’s answer proves nothing. Either way, poll GET /v1/transactions/: a background reconciler consults JDPI §8.4.2 and then commits or cancels the hold, and the money is not settled until the status says so.
WHAT indirectId ACTUALLY MOVES, because it is more than a label. This participant may serve INDIRECT participants — other institutions registered here with POST /v1/indirects that reach SPI through this participant’s ISPB. Naming one on an order changes THREE things at once: the amount is held on that institution’s @pi_{ispb} settlement position instead of on the payer’s own, the persisted order is stamped with that institution so it appears in GET /v1/indirects//transactions, and the response shape changes from 201-plus-plugin-body to 202-plus-JD-body whenever JDPI acknowledges the order. The identifier is ROUTING DATA, not a credential: this participant authenticates you, and guaranteeing that the order really belongs to that institution is your responsibility, not this API’s.
⚠️ indirectId IS REFUSED 422 PIX-0111 WHILE THIS TENANT’S INDIRECT-PARTICIPANTS FEATURE IS SWITCHED OFF, and the refusal names the setting an operator has to turn on. The order is never quietly executed as a DIRECT one: that would hold the amount on the payer’s own position instead of the institution’s @pi_{ispb}, so the money would leave an account you never named, behind a 201. The refusal is decided before the payer is read, so nothing is held and no order is persisted. An order carrying NO indirectId is unaffected.
When the order reaches its outcome, an indirect order may ALSO push a NOTICE to the endpoint that registration carries (delivery.endpointUrl), queued by the background reconciler once JD’s terminal outcome is known — an HTTPS POST forwarding JD’s own result body verbatim, carrying X-Lerian-Signature (‘sha256=’ followed by the hex HMAC-SHA256 of the exact body bytes under the registration’s shared secret) and X-Lerian-Timestamp. Do not build on the notice arriving. No notice is queued at all when this deployment has no outbound queue configured, and none is queued when the outcome carries no JD result body to forward — an order cancelled locally, without a JD answer, is exactly that case. Delivery of a notice that WAS queued is AT-LEAST-ONCE and can still fail permanently while the payment stands. So the institution must dedup on the end-to-end id and treat GET /v1/indirects//transactions, not the notice, as the record of truth: it is the only place an outcome whose notice was never queued becomes visible. A direct order pushes no notice at all.
End-to-end ids: send endToEndId only when you already hold one (from a key lookup or a QR decode), and then payee.key is mandatory with it. Omit it on a manually typed order and SPI mints one — the response carries the minted value. A QR decode is NOT a key lookup: to pay a decoded QR, send the qrCodeType POST /v1/qrcodes/decode answered, together with its endToEndId and payee.key, or the order goes out as a payment by key and the payee cannot conciliate it (JDPI §8.4.1: tpIniciacao 2 for STATIC, 3 for DYNAMIC). qrCodeType is what makes it a QR payment; txId (sent as idConciliacaoRecebedor, verbatim, never trimmed) follows its type: optional on STATIC, required on DYNAMIC. An invalid combination is refused 400 PIX-0061 naming the field, before anything is held: txId without qrCodeType, qrCodeType without payee.key or endToEndId, a STATIC txId that is neither *** nor up to 25 alphanumeric characters (JDPI §8.4.1; a static QR may decode to one, e.g. TX-001, since §8.3.1/§8.3.3 state no charset, and such a txId cannot be sent), a DYNAMIC txId missing or not 26 to 35 alphanumeric characters. The two fields reach SPI orders only: an on-us payee and a transfer to another core of the same ISPB ignore them. Idempotency: the X-Idempotency header is REQUIRED, and it is what makes a retry safe on every branch, on-us included: once an order is recorded under a key, a resend under that key is refused 409 PIX-0029 and moves no money. Keys are scoped to the payer (the organization, plus the indirect participant on an indirect order); a new order needs a new key. Amounts are integer centavos.
Every refusal below is decided before the hold is taken, so it moves ZERO money, except the cross-core answers PIX-0145, PIX-0146 and PIX-0149, which come after the hold and release it; when JDPI refuses the order after the hold exists, the call answers the refusal, the hold is released and the order stays in GET /v1/transactions with status ERROR — or PENDING, when the ledger does not confirm the release, until the background reconciler resolves it; when JDPI’s answer does not prove a refusal (a timeout, a 5xx, a 408, 409 or 422 — except JD’s payment-signature refusals JDPISPI017 and JDPISPI018, which prove one whatever status carries them and are never re-sent), the hold is kept and the order answers 201 PENDING with this plugin’s body, an indirect order included, its final status coming later. The same release follows 409 PIX-0136, refused before JDPI is called when the paying participant’s payment-order signing settings are written but cannot sign (a setting missing, an algorithm this plugin does not sign with, a key that does not fit it, or a certificate that is not the key’s own); the message names the setting, and nothing reaches JDPI unsigned. Refusals: 409 PIX-0029 when this endToEndId or X-Idempotency key was already used by an order that may have moved money, and 409 PIX-0133 when that order was refused and moved none (send a new order under a new key); 409 PIX-0076 when the paying position lacks the amount; 409 PIX-0078 on a transfer to the same account; 409 PIX-0075 when the account’s period limit is exceeded; 422 PIX-0030 on a non-positive amount; 422 PIX-0037 when endToEndId arrives without payee.key; 422 PIX-0108 when the payer — or, on an indirect order, the indirect’s @pi — resolves in the CRM but is not bound to a ledger account; 422 PIX-0111 when an indirectId is supplied while this deployment’s indirect-participants feature is off (naming the setting to enable — the order is refused, never quietly paid from the payer’s own account), 404 PIX-0095 for an unknown or malformed indirectId and 422 PIX-0100 when the indirect it names is not ACTIVE; 422 PIX-0127 when this deployment acts as SEVERAL direct participants and the order names none of them in payerIspb, and 422 PIX-0128 when the one it names is not among them; when the payee banks at the PAYING participant — the order would normally settle internally, never touching SPI — and that participant has declared its ISPB shared with another core, the ownership map says which books hold the account the order names (payee.branch, payee.accountNumber and payee.accountDigit; a payment account, accountType 3, by its account alone), asked before the payee is looked up. When the OTHER core holds it, the order is a cross-core transfer, never sent over SPI: the amount is held on the payer’s account and the order is relayed to that core, answering 201 EXECUTED once it credited the payee, 201 PENDING while its answer is unknown (the hold stays and the background worker resends and settles it; poll GET /v1/transactions), 422 PIX-0145 when it refused the credit and 503 PIX-0146 when the order never reached it — both release the hold, so nothing was debited, and the order stays in GET /v1/transactions with status ERROR (send it again under a new X-Idempotency key); and 409 PIX-0149 when any fee in the package priced on the cross-core route (this leg to the other core of the same participant, priced like a Pix sent to another bank) is configured to deduct from the amount instead of being charged on top (an operator setting) — the applied package is known only once the hold is posted, so this refusal comes after the hold and before anything is relayed: the hold is released and the order stays ERROR, or PENDING until the background worker finishes a release the ledger did not confirm; nothing was debited; and 409 PIX-0150 when the paying ledger holds no @intercore account, the clearing account a cross-core transfer moves through (an operator setting): the ledger refuses the hold, nothing was debited, the order stays ERROR and the message names the organization and ledger to create it in. Otherwise: 422 PIX-0129 when the map holds that account nowhere, 422 PIX-0132 when the order’s account cannot be used to ask (a blank account, a blank branch on anything but a payment account, or one the map refuses as malformed — a retry changes nothing), 503 PIX-0130 when it could not answer (safe to retry: nothing was created) and 502 PIX-0131 when it answered in a form that cannot be acted on; each of these four is refused before anything is held and is NOT rerouted over SPI; an on-us payment WITHOUT payee.key is a payment by bank details, and it is credited on the account payee.branch, payee.accountNumber and payee.accountDigit name — number and digit together, exactly the account an interbank Pix carries — which must belong to payee.document, as the receiving institution checks on an interbank Pix: 404 PIX-2016 when the paying participant holds no such account, 422 PIX-0134 when it belongs to someone else, 422 PIX-0033 when no account is typed, 422 PIX-0108 when it is not bound to a ledger account (a payment account, accountType 3, is looked up by its account alone); an on-us payment WITH payee.key is credited on the account payee.branch, payee.accountNumber and payee.accountDigit name once DICT has confirmed them, checked exactly as a payment by bank details (404 PIX-2016, 422 PIX-0134), while an order naming no account is 422 PIX-0033; 422 PIX-0108 when that payee is not bound to a ledger account; 422 PIX-0102 when payerIspb is supplied on an indirect order and is not the participant recorded at that indirect’s registration; 409 PIX-0105 when the ledger the money leaves from declares no accounting route for the direction; when the payer or the on-us payee cannot be used as the order addresses it, nothing is reserved and the answer names what refused: 422 PIX-0137 when the account is held in a ledger that is not configured for Pix on the paying participant (pay from or to an account on a configured ledger, or have the operator add that ledger to the Pix setup), 422 PIX-0138 when the account’s record does not say which ledger holds it, 422 PIX-0139 when the payer’s record names a different institution than the one paying, 422 PIX-0141 when, on an indirect order, the payer account is not in the ledger the indirect is mounted on, and 409 PIX-0140 when the indirect is mounted on books no longer configured for Pix (an operator setting); a refusal of the payer names the payer account (accountId) in its message, while a refusal of the on-us payee — PIX-0137 or PIX-0138 — names no account, because on a payment by key the payee’s account is one you never saw, so read it as the payee the order addressed; 400 PIX-0061 when the X-Idempotency header is missing, blank or over 255 bytes, when accountId is empty or when an accountType is outside the PIX domain 0..4. Called with a partner credential, the order is also decided by that partner’s own rules for the ledger and the CRM this plugin calls to serve it: 403 PIX-4019 when Midaz refuses the partner and 403 PIX-2025 when the CRM does, the message naming the reason (other_tenant, suspended, no_longer_valid or not_allowed) — grant the partner the missing permission on that service; a partner holding no grant for those services is decided by its Pix grant alone. On an indirect order a JD refusal is passed back with JD’s own status and body instead of a problem+json. An on-us payee who banks at the paying participant but in a DIFFERENT ledger of it is served rather than refused: the amount is reserved on the payer’s ledger, credited on the payee’s ledger, and the reserve is then committed — so the order answers EXECUTED only once both legs landed. Both on-us shapes persist their transaction before the first posting, so their failures are not invisible: an order the ledger refuses answers an error AND leaves a transaction you will find in GET /v1/transactions with status ERROR (it does not count against the account’s period limit: only a hold that reached the ledger does); a same-ledger order whose posting the ledger leaves unknown answers 5xx and stays PENDING until the reconcile worker finds the posting and settles it EXECUTED — a posting the ledger does not show yet never fails the order, because the ledger may record a posting after answering for it; and a cross-ledger order whose credit the payee’s ledger has not yet confirmed delivered is ACCEPTED and still settling: it answers 201 with status PENDING, the money stays held, and the reconcile worker completes it — poll GET /v1/transactions rather than retrying it as a fresh payment. NOT every failure on that branch became a 201, and the exception matters because the money has already moved: when the credit HAS landed and the ledger then leaves the outcome of CLOSING the hold unknown — the settle failed, or a release could not be proved — the order still answers 5xx AND still leaves the transaction PENDING. So a 5xx here never means nothing happened. Poll GET /v1/transactions; if you retry, retry with the SAME X-Idempotency key, because a fresh key is a second payment.
Authorizations
JWT bearer token issued by the identity provider.
Headers
Idempotency key for this payment order: any stable string you choose, up to 255 bytes, sent as the X-Idempotency request header (the same header, by the same name, that MED writes and the Midaz ledger take). REQUIRED: omitting it, sending only whitespace, or sending more than 255 bytes is refused 400 PIX-0061 before anything is read, held or sent. Send the SAME value again to retry the SAME order: once an order is recorded under the key, a resend is answered 409 PIX-0029 and moves no money, whether that order went to SPI or settled on-us, so read its outcome with GET /v1/transactions. Keys are scoped to the payer: the organization, plus the indirect participant on an indirect order. A new order needs a new key. BREAKING CHANGE: this replaces the optional body field clientRequestId, which no longer exists.
"order-2026-09-25-0001"
Body
The Midaz ledger account id of the payer.
"019a1b2c-3d4e-7f60-8a9b-0c1d2e3f4a5b"
Transaction amount in centavos (an integer, e.g. 10050 = R$ 100,50).
10050
The recipient bank data.
Free-text payment description.
"Invoice 42"
SPI end-to-end id. Omit ONLY for a manually-typed payment order: per JDPI §8.4.1 the id does not exist yet and is generated by SPI on this call. If you obtained one from POST /v1/qrcodes/decode (§8.3.3) or from GET /v1/entries/{entryId}/lookup (§8.2.14) you MUST send it: omitting it makes SPI mint a DIFFERENT id, and on a payment by key it makes the order go out as manually typed. The endToEndId alone does NOT make an order a QR payment: a Pix paid from a decoded QR must also send qrCodeType (and txId as qrCodeType requires: optional on STATIC, required on DYNAMIC), or it goes out as a payment by key and the payee cannot conciliate it.
"E1234567890"
Optional registered-indirect identifier (UUID) routing this outbound order through an indirect participant's PIX position. Omit for a direct order. Validated server-side before any money moves; unknown or inactive is rejected. Refused 422 PIX-0111, naming the setting to enable, while this deployment's indirect-participants feature is off — the order is never executed as a direct one, which would hold the funds on the payer's own account instead of the indirect's PIX position.
"3f2504e0-4f89-41d3-9a0c-0305e82c3301"
The ISPB of the institution the money leaves from. This deployment may act as SEVERAL direct SPI participants — one ISPB each, each with its own books — and this field is the only thing on the order that says which of them pays. OPTIONAL while it acts as a single participant: omit it and that one pays. REQUIRED once it acts as several — omitted is 422 PIX-0127, and an ISPB this deployment does not act as is 422 PIX-0128. It is ROUTING DATA you supply and guarantee, exactly like indirectId: never a credential, never read from a header or a path, and it never widens what your token can reach. It also decides what counts as on-us — a payee on the PAYING institution ISPB settles as an internal transfer, a payee on a sibling institution of this same deployment is an ordinary Pix over SPI. On an order carrying indirectId it must be blank or the participant recorded at that indirect's registration, which is not necessarily the deployment default one (422 PIX-0102). Send it as an absent key, not an empty string; an empty value is refused 400 PIX-0061.
^[0-9]{8}$"12345678"
Numeric eTransactionPriority (1=PRIMARY,2=SECONDARY).
1
The qrCodeType POST /v1/qrcodes/decode answered, copied verbatim, on a Pix paid from a QR. It makes the order go out as a QR payment (JDPI §8.4.1 tpIniciacao 2 for STATIC, 3 for DYNAMIC) instead of a payment by key. Requires payee.key and endToEndId, both as the decode answered them. Omit it on a key or a manually typed payment. Validated before anything is held: an invalid combination is refused 400 PIX-0061 naming the field. When the payee banks at the paying institution (an on-us transfer sends no order to SPI) it routes nothing: it is recorded as the initiation type (tpIniciacao) of the TRCK.002 report that on-us Pix owes Bacen. Ignored on a transfer to another core of the same ISPB.
STATIC, DYNAMIC "DYNAMIC"
The txId POST /v1/qrcodes/decode answered, copied verbatim and never trimmed (whitespace is refused 400 PIX-0061); sent to JDPI as idConciliacaoRecebedor so the payee conciliates the payment. Only with qrCodeType (alone it is refused 400 PIX-0061). STATIC: optional, up to 25 alphanumeric characters ([a-zA-Z0-9]); the static default *** is accepted and sent as absent. A static QR may decode to a txId outside that band (e.g. TX-001: JDPI §8.3.1/§8.3.3 state no charset, §8.4.1 does); such a QR cannot be paid as a QR payment, and sending its txId is refused 400 PIX-0061 before anything is held. DYNAMIC: required, 26 to 35 alphanumeric characters.
"KJ8H2ZQ0RX4T7W1N9C3V5B6M8P"
Response
Created
Transaction amount in centavos.
10050
The created transaction id.
"d1f9c0a2-..."
eTransactionStatus name.
"PENDING"
Payment description.
"Invoice 42"
The SPI end-to-end id.
"E1234567890"
Numeric eTransactionFlow (2=CASH_OUT,3=INTRA_PSP).
2
The JDPI request id (external CASH_OUT).
"REQ-123"
Numeric eTransactionPriority.
1

