> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Process an inbound JDPI cash-in

> Registers an inbound PIX credit that JDPI has settled to this participant (JDPI section 9.3.2). JDPI calls it once per received credit, after settlement; it is idempotent on the end-to-end id (the mandatory Chave-Idempotencia header). A redelivery of a credit already settled here, carrying the same amount, receiving account and organization/ledger, answers 200 with the acknowledgement the first delivery got (the same idCreditoSgct and dtHrCreditoSgct) and posts nothing.

On success the credit is posted to the receiving customer's account and the response carries the three section 9.3.2 members: idReqJdPi, idCreditoSgct (the identifier of the credit entry this participant recorded) and dtHrCreditoSgct (when it was recorded). That response is an assertion that the money was booked; there is no field in it for a refusal.

NOT EVERY CREDIT LANDS ON A CUSTOMER ACCOUNT. This participant may also serve INDIRECT participants — other institutions that reach SPI through this participant's ISPB and are registered here with POST /v1/indirects. When recebedor.ispb names one of them and its registration is ACTIVE, the credit is posted to THAT institution's `@pi_{ispb}` settlement position instead of to a customer account. The destination is read from the registry row, never from the payload, and the recorded credit is stamped with the institution it belongs to. The 200 body is identical in both cases, so the response does not tell you which destination was used; that institution's own movements are read with GET /v1/indirects/{indirectId}/transactions.

An indirect credit also queues a NOTICE to the endpoint that registration carries (delivery.endpointUrl): one HTTPS POST forwarding this webhook's JD 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 (the send time in Unix seconds, not covered by the signature).

THE CREDIT IS NOT CONDITIONAL ON THE NOTICE, AND THE NOTICE IS NOT GUARANTEED BY THE CREDIT. When a notice is queued it rides the same database transaction as the credit, so a queued notice always belongs to money that was booked. The reverse does not hold: a credit posts and is answered 200 with NO notice queued at all when this deployment has no outbound queue configured, or when the verbatim JD body could not be retained for forwarding (retention is best-effort — it is skipped for an empty body and abandoned on a write failure, and the credit proceeds either way, because the money is not held hostage to the forwarding). Delivery of a notice that WAS queued is AT-LEAST-ONCE and independent of this 200: the same notice can arrive more than once, and it can also fail permanently while the money stays booked. So a receiving institution must dedup on endToEndId, and must treat GET /v1/indirects/{indirectId}/transactions — not the notice — as the record of truth. Reconciling from that feed is not a fallback for a failed notice; it is the only way to see a movement whose notice was never queued.

Three ordering rules decide the destination and cannot be inferred from the payload:

- A pagador.ispb identifying Bacen (99999) short-circuits FIRST, ahead of any indirect matching, so it never reaches a settlement position either.
- A recebedor.ispb equal to this participant's OWN ISPB is always resolved against this participant's own customer records, never against the indirect registry.
- While this tenant's indirect-participants feature is switched OFF, recebedor.ispb is not read against the registry at all: every credit is resolved ONLY against this participant's own customer records, exactly as before indirect participants existed. Two things follow, and the second is the dangerous one. PIX-0119 becomes unreachable, because nothing consults the registry to find the receiver unserved. And a credit addressed to a registered institution is normally answered 404 PIX-0115, because no customer here holds that account number — but it is NOT refused on the account number alone. Should a local customer hold the same recebedor.nrConta AND the same recebedor.cpfCnpj, the credit is POSTED TO THAT CUSTOMER and answered 200, with the institution's `@pi_{ispb}` never involved; a number that collides under a different holder is refused 409 PIX-0117 instead. Sending recebedor.nrAgencia narrows that further — it is optional in section 9.3.2, and this participant adds it to the account lookup only when you send one, so a credit that omits it is matched on the account number alone. Register the institution AND enable the feature before pointing any credit at it.

A credit that CANNOT be registered is therefore answered with an HTTP error, never with a 200. Each carries a distinct code in the problem body's `code` member:

- 404 PIX-0115 - the receiving account named by the credit was not found here. Check recebedor.nrAgencia/recebedor.nrConta, or recebedor.cpfCnpj when no account coordinates are sent.
- 404 PIX-0119 - recebedor.ispb is neither this participant's own ISPB nor an ACTIVE indirect participant registered in this tenant. It covers both a receiver with no registration at all and one whose registration is not ACTIVE (suspended, closed, or a legacy row that never finished being set up); the two are deliberately not distinguished on the wire, because neither is something the sender can act on differently. It presupposes the indirect-participants feature is ON — with it off nothing consults the registry and this code cannot be answered at all.
- 409 PIX-0116 - recebedor.cpfCnpj names more than one account here, so the destination is undeterminable. Address the credit to specific account coordinates.
- 409 PIX-0117 - the account addressed by recebedor.nrAgencia/recebedor.nrConta belongs to a different holder than recebedor.cpfCnpj names.
- 409 PIX-0118 - the addressed account exists here but is not set up to receive credits.
- 409 PIX-0029 - this end-to-end id was already registered here for a DIFFERENT credit: another amount, another receiving account or another organization/ledger. Nothing was posted for this delivery; the original registration stays unchanged, and its settlement may still be in progress.
- 500 PIX-0120 - a provisioning fault at this participant, not a problem with the request. The credit is safe to redeliver once it is corrected.
- 500 PIX-4011 - whether the credit landed is not settled yet, typically because an earlier delivery of this end-to-end id is still being credited. Nothing more was posted; redeliver, and the redelivery that finds the credit settled gets its acknowledgement.
- 500 PIX-0151 - the receiving account's balance does not accept credits. Nothing was posted; the credit waits, shown PENDING with pendingReason BALANCE_NOT_RECEIVING by GET /v1/transactions, and the first redelivery after the balance accepts credits registers it and gets its acknowledgement.
- 500 PIX-4011 - the receiving participant's own transaction rules (its Tracer) refused the credit. Nothing was posted; the credit waits, shown PENDING with pendingReason TRACER_DENIED by GET /v1/transactions, and the first redelivery after the rules let it through registers it.
- 500 with a dependency code - a service this participant reads through to register the credit did not answer. Section 9.3.2 lists no 503 or 504, so an outage the rest of this API answers 503/504 is answered 500 here, keeping the code and a detail that names the dependency: PIX-3007 (Access Manager timed out) and PIX-3008 (Access Manager unavailable), which authenticate the customer lookup; PIX-2020, PIX-2021 and PIX-2022 (CRM unreachable, timed out, unavailable); PIX-4000, PIX-4001, PIX-4002 and PIX-4010 (Midaz unreachable, timed out, unavailable, balance unreadable). Nothing was posted; redeliver once the dependency recovers.

WHICH OF THOSE AN INDIRECT CREDIT CAN ACTUALLY HIT is a shorter list, because its destination comes from the registry rather than from a customer lookup — and the whole list below presupposes the indirect-participants feature is ON, since with it off there is no indirect path to be on. PIX-0119 is the one: it is what a receiver ISPB with no ACTIVE registration answers, and it exists only on this path. PIX-0115, PIX-0116, PIX-0117, PIX-0118 and PIX-0120 are all decided by the own-customer lookup and are unreachable once recebedor.ispb resolves to an ACTIVE registration — so seeing any of them means the credit was NOT treated as an indirect one. PIX-0029 behaves identically on both paths. A registry read that fails is a 500 like any other dependency failure: nothing is registered, and the credit is safe to redeliver.

Besides the redelivery of a settled credit above, one outcome acknowledges 200 WITHOUT any credit ever being posted: a pagador.ispb identifying Bacen (99999), which this participant nulls by design. Its response carries the acknowledgement echo (idReqSistemaCliente, idReqJdPi, endToEndIdOriginal, endToEndIdDevolucao) and no idCreditoSgct.

Malformed payloads are rejected with 400 at the edge, before any resolution runs: 400 PIX-0061 for a body that fails schema validation, and 400 PIX-0061 for a missing endToEndId, a valor that is not a positive finite amount, or a malformed CPF/CNPJ or ISPB on either participant block.



## OpenAPI

````yaml /pt/openapi/v3-current/pix.yaml post /v1/webhooks/cash-ins
openapi: 3.1.0
info:
  contact:
    email: contact@lerian.studio
    name: Lerian Studio
    url: https://lerian.studio
  description: >-
    The API of a DIRECT Brazilian PIX participant, integrated with BACEN's DICT
    (key directory) and SPI (settlement) rails through JDPI. It covers the
    directory (key entries and claims), payments and devolutions over SPI or
    on-us, per-account limits, QR codes with self-hosted signed payloads, the
    inbound webhooks JDPI calls on this participant, MED 2.0 (BACEN's special
    return mechanism), PIX Automático (recurring payments), and the registry of
    INDIRECT participants served through this participant's ISPB.


    ## Domain map


    - **Entries** / **Claims** — the DICT directory: registering PIX keys, and
    the claim process for taking a key over from another PSP.

    - **Transactions** / **Refunds** / **Limits** / **Banks** — SPI payments:
    outbound orders (two-phase over SPI, synchronous on-us), payee-initiated
    devolutions, per-account outbound limits, and the live SPI participant
    catalog. ⚠️ **BREAKING**: the payer's PIX key is gone from payment orders,
    so a `POST /v1/transactions` body still carrying the top-level `key` is
    refused `400 PIX-0061` (the payee's `payee.key` is unchanged).

    - **QR Codes** — static and immediate dynamic QR codes, decode, and the
    anonymous public routes serving signed payloads to payer PSPs (documented in
    the tag).

    - **Webhooks** — the inbound mirror: cash-in, payee-bank-initiated refund,
    and synchronous account validation, called BY JDPI on this participant.

    - **Indirects** — the institutions this direct participant serves: registry,
    lifecycle, settlement positions, delivery notices, reconciliation feed, and
    the optional own QR certificate.

    - **MED Infractions / Refunds / Recoveries / Fraud Markers** — MED 2.0:
    infraction reports, the refund-request money flow in both roles,
    creator-side value recoveries and DICT fraud markers. A MED settlement
    credit arrives on the §9.3.3 refund webhook under Webhooks.

    - **PIX Automatico** — recurring authorizations, schedules, composite QR
    codes, the inbound registration/validation and settlement legs JDPI calls,
    and the event-stream ingress.

    ## Authentication


    Every operation requires a bearer token minted by the platform's
    machine-to-machine (M2M) OAuth flow with the DIRECT participant's
    credentials; authorization is per resource with actions mirroring the HTTP
    verbs. INDIRECT participants never hold a credential: an indirect's id on a
    request is ROUTING DATA supplied and guaranteed by the direct participant,
    not an authentication principal. The exception to authentication is the
    public QR payload/JWKS routes described under the QR Codes tag, which are
    anonymous by construction — the payer's PSP, not a registered client, is
    their caller.


    ## Money: one API, two units


    Every money field of THIS API's contract is an **int64 count of centavos** —
    in JSON bodies, query, path and header alike (`110001` means R$ 1.100,01).
    Every money field on a body AUTHORED BY JDPI — the inbound webhook mirrors
    under Webhooks and the PIX Automático inbound/settlement/event routes — is a
    **JSON number in reais** (`1100.01`), because that is JD's contract on the
    payloads JD sends, converted to centavos at the boundary. The discriminator
    is WHICH SIDE AUTHORED THE BODY: every money field on this API's own write
    surfaces, MED writes included, is integer centavos. Each field's description
    states its unit.


    ## Accounts


    A request names one of this participant's accounts — an `accountId` field or
    an `account_id` parameter — by its **Midaz ledger account id**: the
    `accountId` its CRM alias records, never the CRM alias's own `id`. It is
    looked up in the books of the participant the request addresses, and an id
    not found there is refused `404 PIX-2016` (`404 PIX-0063` on entry details).
    Two exceptions carry the account's ledger **alias** (`@...`) instead: every
    `accountId` in a response, and the `account_id` filter of the transaction
    list, which matches the alias a row carries and answers an empty list when
    none does.


    ## Errors


    Errors are RFC 9457 `application/problem+json`, and every one carries a
    `PIX-XXXX` taxonomy code in the `code` member — match on the code, not on
    the human-readable text. The status discipline is ATTRIBUTION: a 4xx means
    the request, or the data the request names, is what failed (the body names
    the field or entity); a 5xx names the failing dependency (e.g. `503
    PIX-1050` — the JDPI service is temporarily unavailable) rather than hiding
    behind a generic error; a ledger outage (`PIX-4002`) also carries
    `Retry-After`, in seconds. `500 PIX-0109` is the one deliberate exception:
    an unattributed internal failure, whose detail is scrubbed — as is every
    response body with status 500 or above.


    ## Idempotency


    Three families, each protecting a different leg:


    - **The `X-Idempotency` header** is REQUIRED on payment orders (`POST
    /v1/transactions`), on refunds (`POST /v1/refunds`) and on the ten MED write
    operations, and it is the SAME header, by the same name, that the Midaz
    ledger takes on its transaction routes — one integration, one header. Send
    any stable business string; omitting it is refused `400 PIX-0061` before any
    ledger or JDPI call. On a payment order it is the only identifier that
    exists BEFORE the JDPI call, so it protects every branch, on-us included: a
    resend of an order already recorded under the key — or under its
    `endToEndId` — is refused `409 PIX-0029` and moves no money, and so is a
    resend of a refund already recorded under its key. Payment and refund keys
    are scoped to the payer: the organization, plus the indirect participant on
    an indirect order or refund. ⚠️ **BREAKING**: payment orders and refunds
    took the value as the optional body field `clientRequestId` and MED writes
    as the body field `idempotencyKey`; both fields are gone, and three MED
    writes (cancel a refund request, cancel an infraction, return a recovery)
    now take no request body at all.

    - **The JDPI `Chave-Idempotencia`**: the value you send on `X-Idempotency`
    is a SEED — it is projected to a deterministic GUID (UUIDv5) before being
    forwarded, so one client key always lands in one JDPI dedup slot and a retry
    stays a retry inside JD's 24h window. Correlate JDPI-side logs with the
    projection, never with the raw value. DICT writes derive their key from the
    full request, so a transport retry never double-applies.

    - **Ledger postings** are idempotent per order, namespaced per LEG, so the
    two legs of one devolution (or a debit and its reversal) can never collide
    on one idempotency slot.


    Multi-tenant deployments resolve the tenant from the validated token, never
    from payloads or paths; the public QR routes' ISPB path segment is a routing
    selector for public key material, not an identity.
  license:
    name: Lerian Studio General License
  title: Pix JD API
  version: 1.0.0
servers: []
security:
  - BearerAuth: []
tags:
  - description: >-
      The SPI participant catalog (JDPI §8.6.1), read live from JDPI on every
      call with nothing cached — latency and availability here are JDPI's, and
      an unreachable JDPI answers 503 PIX-1050. Two projections of the same
      catalog: GET /v1/banks is the reduced (ispb, legal name) pair a payment
      form needs; GET /v1/banks/participants is the full record with
      participation type, modality and status. Keep ispb a STRING — it is 8
      characters and its leading zeros are significant.


      This is the NATIONAL directory, not this deployment's own registry: a
      participant classified as indirect here (participantType=2) has no
      relation to the indirect participants registered with POST /v1/indirects,
      and neither list implies membership in the other.
    name: Banks
  - description: >-
      DICT key claims: the BACEN process for taking over a PIX key that is
      currently registered at another PSP — portability of your own key, or an
      ownership claim on a key someone else holds. A claim is a negotiation
      between two PSPs mediated by the DICT, and this surface exposes both sides
      of it: open a claim (POST /v1/claims), list and inspect the ones this
      participant is involved in, confirm (the donor side acknowledging),
      conclude (the claimer side completing the transfer), and cancel.


      Claims move no money — they move DIRECTORY state, and several steps are
      irreversible once the DICT records them: a concluded claim has already
      re-pointed the key at the claiming account. Each operation's description
      states which side of the claim calls it and in which claim status it is
      legal; a step attempted out of order is refused with a coded 4xx rather
      than forwarded to the DICT.
    name: Claims
  - description: >-
      DICT key entries: registering, updating, listing and removing the PIX keys
      — CPF/CNPJ, phone, email or random key (EVP) — that bind an addressable
      alias to one of this participant's accounts in the BACEN directory. The
      surface also carries the verification call (a batch existence check
      against the DICT) and the two bulk-removal flows, account closure (POST
      /v1/account-closures) and holder removal (POST /v1/holder-removals), which
      drop every key bound to a coordinate at once.


      The rule integrators trip on: the DICT locates keys by the FULL account
      coordinate — ISPB, branch, account number AND account type (tpConta) — so
      a lookup or removal that names the wrong account type finds nothing,
      silently: the answer is an empty 200, indistinguishable from an account
      that genuinely holds no keys. Registration is idempotent at JDPI through a
      deterministic idempotency projection, so a transport retry of the same
      request does not double-register a key.
    name: Entries
  - description: >-
      **What this domain is.** This participant is a DIRECT PIX participant, and
      it can serve INDIRECT participants: other institutions that reach SPI and
      the DICT through this participant's ISPB. This surface is the registry of
      those institutions — registering one, suspending, reactivating and closing
      it, reading the key set its QR codes are signed with, and reading the
      reconciliation feed of every movement that rode its settlement position.


      **The credential model, because it decides how you integrate.** An
      indirect participant NEVER holds a credential for this API. Every call is
      authenticated as the direct participant, and the indirect's id on an order
      or a registration row is ROUTING DATA: it decides which settlement
      position the money moves on, and the guarantee that a request really
      belongs to that institution is the direct participant's responsibility,
      made before the request is sent — this API does not re-validate it.


      **Where the money moves.** Registering an institution creates a dedicated
      ledger settlement position for it (its `@pi_{ispb}` account), atomically
      with the registry row. From then on: an outbound order carrying its
      indirectId is HELD on that position (the debit source always comes from
      the registry, never from the caller's body), an inbound credit whose
      receiver ISPB matches it is credited to that position, and the response to
      an indirect order is JD's own acknowledgement passed through verbatim
      (202). The feed at GET /v1/indirects/{indirectId}/transactions is the
      record of truth for all of it: windowed (the `since` bound is required),
      cursor-paged, oldest first, amounts in integer centavos.


      **Lifecycle.** ACTIVE ⇄ SUSPENDED → CLOSED. PATCH carries at most ONE
      lifecycle action per request (suspend, reactivate or close) alongside
      ordinary field updates. Suspending flips the settlement position's
      send/receive flags before the registry row changes, so the ledger
      backstops the registry rather than trailing it. CLOSED is terminal and
      requires the settlement position to hold ZERO balance (409 PIX-0096); the
      position is blocked, never deleted, and re-registering the same ISPB later
      reuses it. Repeating the current state is refused 409 PIX-0094 —
      deliberately not a no-op, so a double-fired automation is visible. One
      ISPB maps to at most one non-CLOSED registration (409 PIX-0093).


      **Delivery notices.** When an indirect's registration carries a delivery
      endpoint, the plugin can push JD's own payload BYTE-FOR-BYTE to it as an
      HTTPS POST carrying X-Lerian-Signature ('sha256=' + the hex HMAC-SHA256 of
      the exact body bytes under the registration's shared secret) and
      X-Lerian-Timestamp. Delivery is AT-LEAST-ONCE: the institution MUST dedup
      on the end-to-end id, and must treat the transactions feed — not the
      notice — as the record of truth, because a notice can fail permanently, or
      never be queued at all, while the payment stands. The shared secret is
      write-only: PATCH replaces it, and every read renders it masked.


      **The QR certificate option, which is commercial, not compliance.** By
      default a QR raised for an indirect is signed with the DIRECT
      participant's certificate and hosted on the direct's domain — the ordinary
      arrangement, and no registration step here is needed for an indirect to
      transact. An institution that opts into its OWN certificate registers it
      via PATCH `qrCertificate`: `ownCertificate: true` plus a scheme-less,
      publicly resolvable `publicBaseUrl` (with the shipped path defaults the
      base URL may spend at most 37 of BACEN's 77-character payload-URL budget —
      measure the hostname BEFORE promising it). The whole sub-object is gated
      on this tenant's indirect-participants feature (off = 422 PIX-0111), and
      it should be switched on only after the certificate is live on BACEN's
      list — before that, payments fail silently at the payer's app, which
      validates a signature nothing vouches for. The institution then hosts its
      own signed payloads AND the key set they validate against: read that key
      set with GET /v1/indirects/{indirectId}/jwks (an authenticated operator
      read; 422 PIX-0114 when the institution has no own certificate — the
      direct participant's public JWKS route serves that case) and serve the
      bytes verbatim. A SUSPENDED institution can still read its key set: QRs
      already in the wild still need validating.


      **Refusals to know.** 404 PIX-0095 unknown (or malformed) indirect id — an
      id belonging to another tenant is deliberately indistinguishable from an
      unknown one; 422 PIX-0100 the institution is not ACTIVE; 422 PIX-0102 a
      payer ISPB on an indirect order names anything but the direct participant
      that institution is mounted on (blank, or that participant's own ISPB, are
      the two accepted values — an indirect's own ISPB is never one of them);
      409 PIX-0093/0094/0096 the lifecycle rules above; 422
      PIX-0111/0112/0113/0114 the QR-certificate rules above; 404 PIX-0119 an
      inbound credit for a receiver this participant does not serve.
    name: Indirects
  - description: >-
      Per-account PIX transaction limits, enforced on OUTBOUND money only. Four
      limit rows exist per account — transaction and period, each in a daily and
      a nightly band — and the day/night boundary comes from this institution's
      policy (whole hours, default 06:00–20:00 UTC as the daily window), not
      from the request.


      A fresh account legitimately answers GET /v1/limits with an empty list and
      GET /v1/limits/available with 404: the rows are seeded with defaults by
      the account's FIRST outbound transaction, not at account creation. An
      account with no rows is therefore NOT unlimited — the enforcer seeds and
      then enforces, failing closed if a limit cannot be established. PATCH
      /v1/limits is update-only: it adjusts a row that exists, and naming a
      (type, period) tuple that has no row yet is refused 422 PIX-0036. A
      payment over the applicable limit is refused 409 PIX-0075 before any money
      moves.
    name: Limits
  - description: >-
      MED 2.0 fraud markers: the DICT records this participant creates against a
      person or key involved in fraud, feeding BACEN's shared fraud database.
      Create a marker (POST /v1/med/fraud-markers), cancel one you created, list
      the local working set, inspect one, and query the DICT's own view (GET
      /v1/med/fraud-markers/dict).


      Markers move no money and have a two-party lifecycle: created here,
      acknowledged/consolidated at the DICT. The write operations take the
      client idempotency key on the `X-Idempotency` request header (required; it
      was a body field `idempotencyKey` until this version, and the cancel
      operation now takes no body at all). It is projected to a deterministic
      GUID before reaching JDPI (see the API description's idempotency section),
      so a retry with the same header value lands in the same JDPI dedup slot.
    name: MED Fraud Markers
  - description: >-
      MED 2.0 infraction reports: the notifications that open BACEN's special
      return mechanism on a transaction — typically fraud reported by the
      payer's PSP against a payment this participant received. Inbound reports
      addressed to this participant are collected from JDPI by a background
      poller and land in the local working set automatically; this surface is
      where you SEE them (list, inspect, read JDPI's own view) and ACT on them
      (analyze — agree or disagree — and cancel one this participant created).


      Infractions move no money themselves; they are the predicate for MED
      Refunds, where the money leg lives. Analysis is subject to a BACEN SLA
      measured from the report's creation, and the write operations take the
      client idempotency key on the `X-Idempotency` request header (required; it
      was a body field `idempotencyKey` until this version, and the cancel
      operation now takes no body at all), projected to a deterministic GUID
      before reaching JDPI.
    name: MED Infractions
  - description: >-
      MED 2.0 value recoveries: the creator-side flow this participant runs when
      its own customer was defrauded and the money went to another PSP — open a
      recovery (POST /v1/med/recoveries), amend it while the counterparty
      analysis allows, and, once the counterparty approves, execute the return
      step (POST /v1/med/recoveries/{idRecValores}/return) within the 72-hour
      window that approval arms. GET /v1/med/recoveries/awaiting-return is the
      operator worklist of recoveries whose clock is running.


      The recovery API at JDPI has no pending-list poll, so open recoveries are
      re-synced by a background poller — local state can trail the counterparty
      by one poll interval. The return step is the money-bearing action of the
      flow; everything else is negotiation state. Write operations take the
      client idempotency key on the `X-Idempotency` request header (required; it
      was a body field `idempotencyKey` until this version, and the return
      operation now takes no body at all), projected to a deterministic GUID
      before reaching JDPI.
    name: MED Recoveries
  - description: >-
      MED 2.0 refund requests: the special-return money flow itself. This
      participant appears in BOTH roles — as the REQUESTING PSP it opens a
      refund request against another PSP (POST /v1/med/refunds); as the
      CONTESTED PSP it receives requests (collected from JDPI by a background
      poller — GET /v1/med/refunds/pending-analysis is the analysis worklist),
      analyzes them within the BACEN SLA, and, when it accepts, EFFECTUATES the
      devolution: POST /v1/med/refunds/{idSolDevolucao}/effectuate debits the
      customer who received the original payment and submits the pacs.004 over
      SPI.


      Effectuation is the money leg, and it is two-phase: the debit is HELD as a
      pending ledger posting when the effectuate call is accepted, and a
      background settlement reconciler commits it when SPI settles (or releases
      it on a terminal SPI error) — so an accepted effectuate is not yet settled
      money, and the row's state says which side of that line it is on.
      Direction is guarded on the participant's own ISPB: only the CONTESTED PSP
      (the PSP whose customer RECEIVED the original payment) can effectuate,
      refused 400 PIX-0088 otherwise, and the mirror credit of a refund this
      participant WON arrives on the §9.3.3 refund webhook (POST
      /v1/webhooks/refunds, codes BE08 and FR01) and credits the original payer.
      GET /v1/med/refunds/credits/{endToEndIdDevolucao} reads that credit's
      landing. Every write except effectuate takes the client idempotency key on
      the `X-Idempotency` request header — the same header the Midaz ledger
      takes — required, and projected to a deterministic GUID before reaching
      JDPI, so correlate JDPI-side logs with the projection, not the raw value
      you sent. It was a body field `idempotencyKey` until this version, and the
      cancel operation now takes no body at all.
    name: MED Refunds
  - description: >-
      PIX Automático: BACEN's recurring-payment arrangement, where a payer
      authorizes a merchant's PSP to pull scheduled payments. This surface
      carries the whole arrangement from this participant's seat: recurring
      authorizations (create, confirm, respond, adjust the max value, cancel),
      the payment schedules under them (create, list, cancel), the composite QR
      codes that carry a charge and a recurrence in one artifact (static,
      dynamic, cobv and recurrence-only, with their updates and decode), the
      `/inbound` registration and validation endpoints JDPI calls on this
      participant per annexes §5.2/§5.3, the §5.4 settlement legs (block, debit,
      and the compensating reversal via DELETE), and the §6 event-stream ingress
      (`/events/*`) through which JDPI pushes lifecycle status.


      Which party calls each route matters more here than anywhere else in the
      API: `/inbound/*`, `/events/*` and `/settlements/*` are called BY JDPI on
      this participant, while the rest are called by your systems. Only the JD
      Courier's credential (sourceService jd-courier), JD's existing application
      (sourceService jd-consultores) or an application the tenant lists as JD's
      (tenant_policy/jd.direct_client_ids) may call those; any other caller is
      403 PIX-0005. The §5.4 settlement legs move money — the debit posts
      against the paying customer, the reversal compensates it — and both are
      idempotent per end-to-end id with the reversal namespaced separately, so
      the two legs of one scheduled payment can never collide. Amounts on this
      participant's own operations are integer centavos; the inbound JDPI
      mirrors carry reais as JSON numbers, per the API-wide two-unit rule.
    name: PIX Automatico
  - description: >-
      **What this domain does.** Creates, updates, decodes and lists this
      participant's PIX QR codes: STATIC (a reusable key-and-optional-amount
      code) and IMMEDIATE DYNAMIC (a single-use charge whose payload is a signed
      JWS document fetched by the payer's PSP at pay time). Due-date charges
      (cobv), withdrawal and change (saque/troco) variants are RECOGNIZED by the
      decode operations but not created here; recurring composites live under
      PIX Automatico.


      **Who signs, who hosts — the part that decides your architecture.** JDPI
      holds the certificate and signs every dynamic payload; this plugin
      composes the URLs the QR carries, and by default it also STORES and SERVES
      the signed JWS on its own public routes, so the QR that comes back is
      end-to-end resolvable with no work on your side. The exception is a charge
      raised for an indirect participant that holds its OWN certificate: the
      signed JWS comes back in the create/update response and is NOT stored —
      that response is the ONLY delivery, and the indirect hosts the document
      (and the matching key set, read via GET /v1/indirects/{id}/jwks) on its
      own domain. If that response is lost, the charge nevertheless exists at
      JDPI: recover it via GET /v1/qrcodes/list (match your
      recipientConciliationId) and PUT /v1/qrcodes/dynamic/{documentId}, which
      re-signs and returns a fresh payloadJws rather than reproducing the lost
      one.


      **The dynamic-QR lifecycle.** Create validates everything BEFORE calling
      JDPI — the recipient's name and city come from this participant's CRM
      records, never from the body; the payload URL is composed first because
      JDPI requires it in the request; the conciliation id must be new (409
      PIX-0065) — so a refused create never leaves a charge behind, and a JDPI
      failure after persistence is compensated by deleting the local row. Update
      (JDPI §8.3.5) changes the amount, conciliation, expiration, payer or
      charge status (0=Active, 1=Concluded, 2=Removed by recipient, 3=Removed by
      PSP), and REUSES the location: a printed QR keeps resolving, because the
      updated JWS atomically supersedes the old one at the same path id. The
      plugin stores no charge↔indirect association, so EACH update's indirectId
      decides who signs that revision — omitting it on an indirect-hosted charge
      moves the charge onto the direct participant's certificate and domain.


      **The 77-character budget.** BACEN caps the payload URL (urlPayloadJson)
      at 77 characters, scheme-less, and the path this deployment is configured
      with spends most of it. An over-budget URL is refused by ATTRIBUTION: 422
      PIX-0112 when an indirect's registered base URL is what does not fit
      (choose the hostname against the remaining allowance BEFORE registering
      it), 500 PIX-0053 when the deployment's own configuration leaves no room
      for any charge.


      **Decode and list.** Decode accepts the scanned EMV payload (POST
      /v1/qrcodes/decode) or the payload URL itself (POST
      /v1/qrcodes/decode/url), per §8.3.10. GET /v1/qrcodes/list (§8.3.12)
      requires a bounded registration window of at most 90 days; omitting the
      type fans the query out across every QR type.


      **Public payload & JWKS routes.** Four routes exist OUTSIDE this
      specification — they are anonymous, they are called by the PAYER'S PSP
      (never by you), and they are listed here because they are part of the
      deployment's public contract even though no operation below describes
      them. Their path prefixes (the payload path and the JWK path) and their
      host vary per deployment; the shapes are:


      - `GET /{payloadPath}/cob/{id}` (single-tenant form) and `GET
      /{payloadPath}/{ispb}/cob/{id}` (multi-tenant form, where the ISPB segment
      selects the serving participant) — the signed JWS payload of one dynamic
      charge, returned raw with Content-Type `application/jose`. The `cob`
      segment is LITERAL: only immediate charges are self-hosted, and a `cobv`
      fetch answers 404 rather than handing the payer's PSP a resource of a type
      it did not ask for.

      - `GET /{jwkPath}` (single-tenant) and `GET /{jwkPath}/{ispb}`
      (multi-tenant) — the JWK Set the payloads validate against, as
      `application/jwk-set+json`, served from a short-lived cache (minutes) over
      JDPI's key material.


      The 22-character `{id}` is a cryptographically random token minted per
      charge, and it is the route's only barrier: unguessable by construction,
      it acts as a capability — knowing the URL is what authorizes the fetch,
      which is exactly the EMV model, where the URL travels inside the QR. A
      missing, expired or unknown payload — and an unknown ISPB — answer a
      UNIFORM 404 with code PIX-0063, deliberately not distinguishing absent
      from expired: a payer PSP must not pay an expired QR, and nothing more is
      anyone else's business. Server-side faults (the participant lookup
      unavailable, JDPI unreachable with nothing cached) answer 503. Errors on
      these routes are RFC 9457 problem+json like everywhere else.
    name: QR Codes
  - description: >-
      Refund of a RECEIVED PIX payment — the BACEN rule is that refunds are
      PAYEE-initiated, and this surface encodes it: only the party that received
      the money can return it. A refund never mutates the original transaction;
      it is a NEW transaction row (is_refund=true) whose amount is capped at the
      original minus every prior refund of it (409 PIX-0075 over the cap). GET
      /v1/refunds/reasons is the catalog of accepted devolution reason codes.


      Refunding a payment sent to another institution is refused 400 PIX-0089,
      or 400 PIX-0087 when the requester is the customer who sent it (ask the
      payee's PSP instead — or, for the special return mechanism, see MED
      Refunds); for any other original, a requester who is not its payee is
      refused 400 PIX-0088. An on-us original settles the return synchronously
      in the ledger; an original that arrived over SPI is returned through JDPI
      first, and the ledger posting follows JD's acceptance.
    name: Refunds
  - description: >-
      **What this domain does.** Outbound PIX payments — over SPI to any other
      participant, or settled on this participant's own book when the payee is
      on-us — plus the read surface that closes the loop on them. The Refunds
      and Limits tags are part of the same flow: a devolution is a new
      transaction row, and limits are enforced here on the way out.


      **The lifecycle, and which flow settles when.** A transaction's status is
      PENDING (0), EXECUTED (2) or ERROR (-1), and the only real edge is PENDING
      → EXECUTED or ERROR. An on-us (INTRA_PSP) order settles SYNCHRONOUSLY: one
      final ledger posting, answered 201 already EXECUTED. An external CASH_OUT
      is the API's only TWO-PHASE money flow: the amount is HELD on the paying
      position as a pending ledger debit BEFORE JDPI is called; if JDPI refuses
      the order the hold is released immediately and nothing persists; if JDPI
      accepts (§8.4.1, asynchronous by design) the order persists PENDING, and a
      background reconciler polls JDPI (§8.4.2) on a short tick — settlement (JD
      processing status 9) commits the hold and flips the row EXECUTED, a
      terminal SPI error (-1) releases the hold and flips it ERROR. EXECUTED and
      ERROR are terminal. Inbound credits (CASH_IN) appear in this feed already
      EXECUTED — they settled when the webhook posted them.


      **What that means for a client.** A 201/202 on POST /v1/transactions is an
      ACCEPTED order, not settled money: poll GET
      /v1/transactions/{transactionId} until the status is terminal. PENDING
      means "SPI has not decided", never "stuck" — the reconciler acts on its
      own tick and the status read is side-effect-free. An indirect order
      (indirectId in the body) answers 202 with JD's own acknowledgement
      verbatim instead of the 201-plus-plugin-body of a direct order; handle
      both shapes.


      **Rules you cannot guess from the schemas.** (1) Amounts are integer
      centavos everywhere on this surface. (2) Send endToEndId only when you
      already hold one — from a key lookup or a QR decode — and then payee.key
      is mandatory with it (422 PIX-0037 otherwise); omit it on a manually typed
      order: SPI mints one, or this plugin does when it signs the paying
      participant's orders, and the response carries it either way. To pay a PIX
      key, look it up first with GET /v1/entries/{entryId}/lookup (§8.2.14) and
      send its payee object and its endToEndId on the order: that pair is what
      makes the payment one initiated by key. A payment by key whose payee banks
      at the paying institution is checked against DICT before it settles:
      coordinates that are not the key's account are refused 422 PIX-0033 naming
      the field, and JDPI unavailable is 503 PIX-1050. (3) The X-Idempotency
      header is REQUIRED (400 PIX-0061 without it) and is the only identifier
      that exists BEFORE the JD call, so it is what makes a retry safe on every
      branch, on-us included; a resend under a key already recorded (or a reused
      endToEndId) is refused 409 PIX-0029 and moves no money. (4) Every refusal
      is decided before the hold is taken, so a refused order moves ZERO money.
      (5) The list endpoint has NO pagination — the whole matching set arrives
      in one array, so filter narrowly; and on a CASH_IN row account_id records
      the ledger alias credited rather than a CRM account id, so correlate
      inbound rows by end_to_end_id.


      **Errors that matter.** 400 PIX-0061 missing X-Idempotency header; 409
      PIX-0029 duplicate endToEndId/X-Idempotency key; 409 PIX-0076 insufficient
      balance on the paying position; 409 PIX-0075 period limit exceeded; 409
      PIX-0078 transfer to the same account; 422 PIX-0030 non-positive amount;
      422 PIX-0033 the payee resolves to more than one account (on-us) — refused
      rather than guessed; 422 PIX-0108 a party resolves in the CRM but is bound
      to no ledger account; 404 PIX-0095 / 422 PIX-0100 unknown / not-ACTIVE
      indirect; 503 PIX-1050 JDPI unreachable (the dependency is named, and the
      order was not placed).
    name: Transactions
  - description: >-
      **What this domain is — and is not.** The INBOUND mirror of the JD
      integration: the three endpoints JDPI calls on THIS participant. It is not
      client webhook management — there is nothing to subscribe to here. The
      callers of these routes are JDPI's systems, authenticated with the same
      bearer scheme as everything else; they are documented so an integrator can
      recognize the flows, and so the counterparty configuration names the right
      paths. Only the JD Courier's credential (sourceService jd-courier), JD's
      existing application (sourceService jd-consultores) or an application the
      tenant lists as JD's (tenant_policy/jd.direct_client_ids) may call these
      routes; any other caller is 403 PIX-0005.


      **The three flows.** POST /v1/webhooks/cash-ins is the §9.3.2 inbound
      credit: money received by this participant or by an indirect it serves.
      POST /v1/webhooks/refunds is the §9.3.3 payee-bank-initiated refund of a
      payment this participant SENT: JD has already executed the return when
      this arrives. A MED refund (codes BE08 and FR01) arrives on the same route
      and credits the same original payer, booked on the MED clearing account.
      POST /v1/webhooks/validates is the §9.3.1 synchronous account validation:
      a preflight the payer's PSP runs before sending money.


      **Money arrives in REAIS here.** These bodies are authored by JD, so their
      money fields are JSON numbers in reais (converted to integer centavos at
      the boundary) — the mirror exception to the API-wide centavos rule.
      Everything this API itself answers or persists is centavos.


      **Acknowledged is not credited.** The §9.3.2/§9.3.3 success
      acknowledgement carries the triad idReqJdPi / idCreditoSgct /
      dtHrCreditoSgct, and the field that says money landed is idCreditoSgct.
      The one 200 WITHOUT it is the short-circuit for a payer settled by BACEN
      itself (ISPB 99999), which acknowledges without crediting. Refusals are
      ordinary coded HTTP errors — this surface does not hide a refusal inside a
      200.


      **How a cash-in resolves, in order.** BACEN payer → acknowledge without
      credit. Receiver on this participant's OWN ISPB → own-book credit, located
      by the ADDRESSED coordinates (branch + account number; the receiver
      document is cross-checked, not used to search — a divergence refuses
      rather than re-routes). Receiver ISPB matching an ACTIVE indirect
      participant → credit to that institution's settlement position, with the
      delivery notice recorded in the same unit of work. Anything else — an ISPB
      this participant does not serve — is REFUSED 404 PIX-0119; money is never
      parked or blindly posted. The credit is posted to the ledger BEFORE the
      acknowledgement is returned, and redelivery is deduplicated on endToEndId
      (409 PIX-0029 names a replay of a different payload; an identical replay
      of a settled credit is acknowledged idempotently). Other refusals name
      what failed to resolve: 404 PIX-0115 no account at the addressed
      coordinates, 409 PIX-0116 the coordinates resolve ambiguously, 409
      PIX-0117 the addressed account belongs to a different holder than the
      payload names, 409 PIX-0118 the account cannot be credited.


      **The refund leg holds a PARK.** A returned payment whose original is
      already EXECUTED credits the original payer immediately. One whose
      original is still PENDING (the outbound settlement race) is acknowledged
      200 and PARKED durably — the acknowledgement's idCreditoSgct carries the
      park id — and a background sweep completes the credit once the original
      settles, or escalates it if the original ends in ERROR.


      **Validation always answers 200.** Every §9.3.1 outcome is a 200 whose
      body carries the verdict and reason: DUPL for a second payment of a
      charge, paid within 24h or held in flight by another order (never for a
      static QR, tpIniciacao 2 or 10, which takes any number of payments), BE17
      for a payer mismatch on the referenced charge, AC03 for an account that
      does not resolve, BE01 for a document that diverges from the account's
      holder, AC07 / AC06 for an account its ledger holds closed / blocked. An
      HTTP error from this route means infrastructure, never "account invalid".
    name: Webhooks
paths:
  /v1/webhooks/cash-ins:
    post:
      tags:
        - Webhooks
      summary: Process an inbound JDPI cash-in
      description: >-
        Registers an inbound PIX credit that JDPI has settled to this
        participant (JDPI section 9.3.2). JDPI calls it once per received
        credit, after settlement; it is idempotent on the end-to-end id (the
        mandatory Chave-Idempotencia header). A redelivery of a credit already
        settled here, carrying the same amount, receiving account and
        organization/ledger, answers 200 with the acknowledgement the first
        delivery got (the same idCreditoSgct and dtHrCreditoSgct) and posts
        nothing.


        On success the credit is posted to the receiving customer's account and
        the response carries the three section 9.3.2 members: idReqJdPi,
        idCreditoSgct (the identifier of the credit entry this participant
        recorded) and dtHrCreditoSgct (when it was recorded). That response is
        an assertion that the money was booked; there is no field in it for a
        refusal.


        NOT EVERY CREDIT LANDS ON A CUSTOMER ACCOUNT. This participant may also
        serve INDIRECT participants — other institutions that reach SPI through
        this participant's ISPB and are registered here with POST /v1/indirects.
        When recebedor.ispb names one of them and its registration is ACTIVE,
        the credit is posted to THAT institution's `@pi_{ispb}` settlement
        position instead of to a customer account. The destination is read from
        the registry row, never from the payload, and the recorded credit is
        stamped with the institution it belongs to. The 200 body is identical in
        both cases, so the response does not tell you which destination was
        used; that institution's own movements are read with GET
        /v1/indirects/{indirectId}/transactions.


        An indirect credit also queues a NOTICE to the endpoint that
        registration carries (delivery.endpointUrl): one HTTPS POST forwarding
        this webhook's JD 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 (the send time in
        Unix seconds, not covered by the signature).


        THE CREDIT IS NOT CONDITIONAL ON THE NOTICE, AND THE NOTICE IS NOT
        GUARANTEED BY THE CREDIT. When a notice is queued it rides the same
        database transaction as the credit, so a queued notice always belongs to
        money that was booked. The reverse does not hold: a credit posts and is
        answered 200 with NO notice queued at all when this deployment has no
        outbound queue configured, or when the verbatim JD body could not be
        retained for forwarding (retention is best-effort — it is skipped for an
        empty body and abandoned on a write failure, and the credit proceeds
        either way, because the money is not held hostage to the forwarding).
        Delivery of a notice that WAS queued is AT-LEAST-ONCE and independent of
        this 200: the same notice can arrive more than once, and it can also
        fail permanently while the money stays booked. So a receiving
        institution must dedup on endToEndId, and must treat GET
        /v1/indirects/{indirectId}/transactions — not the notice — as the record
        of truth. Reconciling from that feed is not a fallback for a failed
        notice; it is the only way to see a movement whose notice was never
        queued.


        Three ordering rules decide the destination and cannot be inferred from
        the payload:


        - A pagador.ispb identifying Bacen (99999) short-circuits FIRST, ahead
        of any indirect matching, so it never reaches a settlement position
        either.

        - A recebedor.ispb equal to this participant's OWN ISPB is always
        resolved against this participant's own customer records, never against
        the indirect registry.

        - While this tenant's indirect-participants feature is switched OFF,
        recebedor.ispb is not read against the registry at all: every credit is
        resolved ONLY against this participant's own customer records, exactly
        as before indirect participants existed. Two things follow, and the
        second is the dangerous one. PIX-0119 becomes unreachable, because
        nothing consults the registry to find the receiver unserved. And a
        credit addressed to a registered institution is normally answered 404
        PIX-0115, because no customer here holds that account number — but it is
        NOT refused on the account number alone. Should a local customer hold
        the same recebedor.nrConta AND the same recebedor.cpfCnpj, the credit is
        POSTED TO THAT CUSTOMER and answered 200, with the institution's
        `@pi_{ispb}` never involved; a number that collides under a different
        holder is refused 409 PIX-0117 instead. Sending recebedor.nrAgencia
        narrows that further — it is optional in section 9.3.2, and this
        participant adds it to the account lookup only when you send one, so a
        credit that omits it is matched on the account number alone. Register
        the institution AND enable the feature before pointing any credit at it.


        A credit that CANNOT be registered is therefore answered with an HTTP
        error, never with a 200. Each carries a distinct code in the problem
        body's `code` member:


        - 404 PIX-0115 - the receiving account named by the credit was not found
        here. Check recebedor.nrAgencia/recebedor.nrConta, or recebedor.cpfCnpj
        when no account coordinates are sent.

        - 404 PIX-0119 - recebedor.ispb is neither this participant's own ISPB
        nor an ACTIVE indirect participant registered in this tenant. It covers
        both a receiver with no registration at all and one whose registration
        is not ACTIVE (suspended, closed, or a legacy row that never finished
        being set up); the two are deliberately not distinguished on the wire,
        because neither is something the sender can act on differently. It
        presupposes the indirect-participants feature is ON — with it off
        nothing consults the registry and this code cannot be answered at all.

        - 409 PIX-0116 - recebedor.cpfCnpj names more than one account here, so
        the destination is undeterminable. Address the credit to specific
        account coordinates.

        - 409 PIX-0117 - the account addressed by
        recebedor.nrAgencia/recebedor.nrConta belongs to a different holder than
        recebedor.cpfCnpj names.

        - 409 PIX-0118 - the addressed account exists here but is not set up to
        receive credits.

        - 409 PIX-0029 - this end-to-end id was already registered here for a
        DIFFERENT credit: another amount, another receiving account or another
        organization/ledger. Nothing was posted for this delivery; the original
        registration stays unchanged, and its settlement may still be in
        progress.

        - 500 PIX-0120 - a provisioning fault at this participant, not a problem
        with the request. The credit is safe to redeliver once it is corrected.

        - 500 PIX-4011 - whether the credit landed is not settled yet, typically
        because an earlier delivery of this end-to-end id is still being
        credited. Nothing more was posted; redeliver, and the redelivery that
        finds the credit settled gets its acknowledgement.

        - 500 PIX-0151 - the receiving account's balance does not accept
        credits. Nothing was posted; the credit waits, shown PENDING with
        pendingReason BALANCE_NOT_RECEIVING by GET /v1/transactions, and the
        first redelivery after the balance accepts credits registers it and gets
        its acknowledgement.

        - 500 PIX-4011 - the receiving participant's own transaction rules (its
        Tracer) refused the credit. Nothing was posted; the credit waits, shown
        PENDING with pendingReason TRACER_DENIED by GET /v1/transactions, and
        the first redelivery after the rules let it through registers it.

        - 500 with a dependency code - a service this participant reads through
        to register the credit did not answer. Section 9.3.2 lists no 503 or
        504, so an outage the rest of this API answers 503/504 is answered 500
        here, keeping the code and a detail that names the dependency: PIX-3007
        (Access Manager timed out) and PIX-3008 (Access Manager unavailable),
        which authenticate the customer lookup; PIX-2020, PIX-2021 and PIX-2022
        (CRM unreachable, timed out, unavailable); PIX-4000, PIX-4001, PIX-4002
        and PIX-4010 (Midaz unreachable, timed out, unavailable, balance
        unreadable). Nothing was posted; redeliver once the dependency recovers.


        WHICH OF THOSE AN INDIRECT CREDIT CAN ACTUALLY HIT is a shorter list,
        because its destination comes from the registry rather than from a
        customer lookup — and the whole list below presupposes the
        indirect-participants feature is ON, since with it off there is no
        indirect path to be on. PIX-0119 is the one: it is what a receiver ISPB
        with no ACTIVE registration answers, and it exists only on this path.
        PIX-0115, PIX-0116, PIX-0117, PIX-0118 and PIX-0120 are all decided by
        the own-customer lookup and are unreachable once recebedor.ispb resolves
        to an ACTIVE registration — so seeing any of them means the credit was
        NOT treated as an indirect one. PIX-0029 behaves identically on both
        paths. A registry read that fails is a 500 like any other dependency
        failure: nothing is registered, and the credit is safe to redeliver.


        Besides the redelivery of a settled credit above, one outcome
        acknowledges 200 WITHOUT any credit ever being posted: a pagador.ispb
        identifying Bacen (99999), which this participant nulls by design. Its
        response carries the acknowledgement echo (idReqSistemaCliente,
        idReqJdPi, endToEndIdOriginal, endToEndIdDevolucao) and no
        idCreditoSgct.


        Malformed payloads are rejected with 400 at the edge, before any
        resolution runs: 400 PIX-0061 for a body that fails schema validation,
        and 400 PIX-0061 for a missing endToEndId, a valor that is not a
        positive finite amount, or a malformed CPF/CNPJ or ISPB on either
        participant block.
      operationId: createWebhookCashIn
      parameters:
        - description: >-
            Idempotency key (= the endToEndId of the transaction). Mandatory per
            section 9.3.2.
          in: header
          name: Chave-Idempotencia
          required: true
          schema:
            description: >-
              Idempotency key (= the endToEndId of the transaction). Mandatory
              per section 9.3.2.
            examples:
              - E0435879820200123221500000000001
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CashInBody'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashInResponse'
          description: OK
        '400':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Bad Request
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Forbidden
        '404':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Not Found
        '409':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Conflict
        '413':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Request Entity Too Large
        '500':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Internal Server Error
components:
  schemas:
    CashInBody:
      additionalProperties: true
      properties:
        chave:
          description: The PIX key (present for key-initiated cash-ins).
          examples:
            - recipient@bank.com
          type: string
        cnpjIniciadorPagamento:
          description: Payment initiator CNPJ (a v5.5.0 string).
          examples:
            - '11144477735'
          type: string
        dtContabil:
          description: Accounting date (optional).
          examples:
            - '2026-06-20'
          type: string
        dtHrLiquidacao:
          description: Settlement timestamp (optional).
          examples:
            - '2026-06-20T10:00:01Z'
          type: string
        dtHrOp:
          description: Operation timestamp (ISO-8601).
          examples:
            - '2026-06-20T10:00:00Z'
          type: string
        endToEndId:
          description: SPI end-to-end id (idempotency + dedup key).
          examples:
            - E2E-1
          type: string
        finalidade:
          description: Finality (eFinality).
          examples:
            - 0
          format: int64
          type: integer
        idConciliacaoRecebedor:
          description: Recipient conciliation id (stamped on the row + the 24h marker).
          examples:
            - CONC-1
          type: string
        idReqJdPi:
          description: JDPI request id (becomes the local row id when a UUID).
          examples:
            - JDPI-1
          type: string
        infEntreClientes:
          description: Free-text inter-client info.
          examples:
            - note
          type: string
        ispbPss:
          description: Saque/troco PSS participant ISPB (a v5.5.0 string).
          examples:
            - '12345678'
          type: string
        modalidadeAgente:
          description: Agent modality (eModalityAgent).
          examples:
            - 0
          format: int64
          type: integer
        pagador:
          $ref: '#/components/schemas/PayerBlock'
          description: The payer participant block.
        prioridadePagamento:
          description: Payment priority (ePaymentPriority).
          examples:
            - 0
          format: int64
          type: integer
        recebedor:
          $ref: '#/components/schemas/PayeeBlock'
          description: The receiver participant block (the credit account source).
        tpIniciacao:
          description: >-
            Payment initiation mechanism (section 9.3.2): 0 manual, 1 chave, 2
            QR Code estatico, 3 QR Code dinamico, 6 ITP, 8 Pix Automatico, 9/10
            Pix por aproximacao. Both QR values (2 and 3) book the credit on the
            QR route pair; every other value books on the key route pair.
          examples:
            - 0
          format: int64
          type: integer
        tpPrioridadePagamento:
          description: Payment priority type.
          examples:
            - 0
          format: int64
          type: integer
        valor:
          description: Amount in reais (a JSON number).
          examples:
            - 100.5
          format: double
          type: number
        vlrDetalhe:
          description: Optional value-detail entries.
          items:
            $ref: '#/components/schemas/ValueDetailBlock'
          type:
            - array
            - 'null'
      required:
        - idReqJdPi
        - endToEndId
        - tpIniciacao
        - pagador
        - recebedor
        - dtHrOp
        - valor
      type: object
    CashInResponse:
      additionalProperties: false
      properties:
        dtHrCreditoSgct:
          description: >-
            SGCT credit timestamp (aaaa-mm-ddTHH:mm:ss.sssZ, UTC), on a credited
            result.
          examples:
            - '2026-06-20T10:00:01.000Z'
          type: string
        dtHrReqJdPi:
          description: Request timestamp (ISO-8601).
          examples:
            - '2026-06-20T10:00:00Z'
          type: string
        endToEndIdDevolucao:
          description: Echoed return end-to-end id.
          examples:
            - E2E-1
          type: string
        endToEndIdOriginal:
          description: Echoed original end-to-end id.
          examples:
            - E2E-1
          type: string
        idCreditoSgct:
          description: SGCT credit lançamento id (GUID), on a credited result.
          examples:
            - SGCT-1
          type: string
        idReqJdPi:
          description: Echoed JDPI request id.
          examples:
            - JDPI-1
          type: string
        idReqSistemaCliente:
          description: Echoed client-system request id.
          examples:
            - JDPI-1
          type: string
      type: object
    Detail:
      additionalProperties: true
      properties:
        code:
          description: >-
            Stable, machine-readable domain error code scoped to the emitting
            service (format: <SERVICE>-NNNN).
          type: string
        detail:
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          examples:
            - Property foo is required but is missing.
          type: string
        errors:
          description: Optional list of individual error details
          items:
            $ref: '#/components/schemas/ErrorDetail'
          type:
            - array
            - 'null'
        instance:
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          examples:
            - https://example.com/error-log/abc123
          format: uri
          type: string
        status:
          description: HTTP status code
          examples:
            - 400
          format: int64
          type: integer
        title:
          description: >-
            A short, human-readable summary of the problem type. This value
            should not change between occurrences of the error.
          examples:
            - Bad Request
          type: string
        type:
          default: about:blank
          description: A URI reference to human-readable documentation for the error.
          examples:
            - https://example.com/errors/example
          format: uri
          type: string
        upstream:
          $ref: '#/components/schemas/Upstream'
          description: >-
            RFC 9457 extension member: the error a proxied third-party provider
            reported. Absent unless the emitting service explicitly surfaced
            one.
      type: object
    PayerBlock:
      additionalProperties: true
      properties:
        cpfCnpj:
          description: Payer document CPF/CNPJ (a v5.5.0 string).
          examples:
            - '11144477735'
          type: string
        ispb:
          description: Payer participant ISPB (a v5.5.0 string).
          examples:
            - '12345678'
          type: string
        nome:
          description: Payer name (Obrg=Sim on the pagador block).
          examples:
            - Jane Doe
          type: string
        nrAgencia:
          description: Agency/branch number (the participant branch source; Obrg=Nao).
          examples:
            - '0001'
          type: string
        nrConta:
          description: Account number (NEVER used as the branch).
          examples:
            - '1234567'
          type: string
        tpConta:
          description: >-
            Account type (eAccountType: 0=checking). §9.3.2 Obrg=Sim, but no
            code reads it, so it is tolerated-absent.
          examples:
            - 0
          format: int64
          type: integer
        tpPessoa:
          description: >-
            Person type (ePersonType: 0=natural, 1=legal). §9.3.2 Obrg=Sim, but
            no code reads it, so it is tolerated-absent.
          examples:
            - 0
          format: int64
          type: integer
      required:
        - ispb
        - cpfCnpj
        - nome
        - nrConta
      type: object
    PayeeBlock:
      additionalProperties: true
      properties:
        cpfCnpj:
          description: Receiver document CPF/CNPJ (a v5.5.0 string).
          examples:
            - '11144477735'
          type: string
        ispb:
          description: Receiver participant ISPB (a v5.5.0 string).
          examples:
            - '12345678'
          type: string
        nrAgencia:
          description: Agency/branch number (the participant branch source; Obrg=Nao).
          examples:
            - '0001'
          type: string
        nrConta:
          description: Account number (NEVER used as the branch).
          examples:
            - '1234567'
          type: string
        tpConta:
          description: >-
            Account type (eAccountType: 0=checking). §9.3.2 Obrg=Sim, but no
            code reads it, so it is tolerated-absent.
          examples:
            - 0
          format: int64
          type: integer
        tpPessoa:
          description: >-
            Person type (ePersonType: 0=natural, 1=legal). §9.3.2 Obrg=Sim, but
            no code reads it, so it is tolerated-absent.
          examples:
            - 0
          format: int64
          type: integer
      required:
        - ispb
        - cpfCnpj
        - nrConta
      type: object
    ValueDetailBlock:
      additionalProperties: true
      properties:
        tipo:
          description: Value-detail type.
          examples:
            - 0
          format: int64
          type: integer
        vlrTarifaDinheiroCompra:
          description: Cash-purchase fee amount (reais).
          examples:
            - 0
          format: double
          type: number
      required:
        - vlrTarifaDinheiroCompra
        - tipo
      type: object
    ErrorDetail:
      additionalProperties: false
      properties:
        location:
          description: >-
            Where the error occurred, e.g. 'body.items[3].tags' or
            'path.thing-id'
          type: string
        message:
          description: Error message text
          type: string
        value:
          description: The value at the given location
      type: object
    Upstream:
      additionalProperties: false
      properties:
        code:
          description: The upstream provider's own error code, verbatim.
          examples:
            - E4001
          type: string
        message:
          description: >-
            The upstream provider's own error message, verbatim (bounded, never
            its raw response body).
          examples:
            - account not found at provider
          type: string
      type: object
  securitySchemes:
    BearerAuth:
      bearerFormat: JWT
      description: JWT bearer token issued by the identity provider.
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.