> ## 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.

# Create an immediate dynamic PIX QR code

> Generates an immediate dynamic PIX QR code and persists its conciliation metadata. The plugin sends the JWS host URLs (urlPayloadJson / urlJwk) to JDPI and self-hosts the signed JWS, so the returned QR is end-to-end resolvable; the response carries the resolvable payload URL the EMV embeds. cobv (due-date) and saque/troco variants are not supported.

WHAT indirectId DECIDES HERE IS WHO SERVES THE QR, and it is a decision about hosting rather than about whose charge it is. This participant may serve INDIRECT participants — institutions registered with POST /v1/indirects. Most of them need nothing here: by default a QR raised for one of them is signed with THIS participant's certificate and its payload is hosted on THIS participant's domain, which is the ordinary arrangement and the one nearly every institution wants. An institution that has opted into holding its OWN certificate is the exception, and only for it does indirectId change anything: JDPI then signs with that institution's certificate, the payload URL is built on that institution's own domain, and the signed document comes back to you to host there. Certificate and domain are ONE decision, never two — the payer's app validates the signature against the certificate published at the domain that answered, so signing with one party's certificate while hosting on another's does not validate.

⚠️ indirectId IS SILENTLY IGNORED WHILE THIS TENANT'S INDIRECT-PARTICIPANTS FEATURE IS SWITCHED OFF: the value is not parsed, not resolved and not refused, and the QR is signed and hosted by the direct participant as if you had sent none. Nothing in the response says the routing was dropped. Naming an id and getting 404 PIX-0095 back is the evidence the feature is on.

Refusals specific to indirectId, all decided before JDPI is called so a refused QR is never generated: 404 PIX-0095 for an id that addresses no institution registered in this tenant (a malformed UUID lands here too — it can address none); 422 PIX-0100 when the institution it names is not ACTIVE; 422 PIX-0113 when that institution's registered public base URL names a host a payer's app cannot resolve; 422 PIX-0112 when the composed payload URL exceeds the 77 characters BACEN allows — the path this participant is configured with spends most of that budget, so an institution's hostname must be chosen against the remaining allowance BEFORE it is registered, not after.

When indirectId names an indirect that hosts its OWN certificate, the signed JWS comes back in payloadJws and the plugin does NOT store it — the indirect hosts it at payloadUrl on its own infrastructure, so THIS RESPONSE IS THE ONLY DELIVERY OF IT. If the response never reaches you (client timeout, connection reset, proxy error) the charge nevertheless exists at JDPI, and re-sending the same recipientConciliationId is refused as a duplicate (PIX-0065). Recover it, do not re-create it: call GET /v1/qrcodes/list with qrCodeType 12 over the registration window, match your own recipientConciliationId to read its documentId, then call PUT /v1/qrcodes/dynamic/{documentId} with the SAME indirectId — the update re-signs the charge and returns a fresh payloadJws (JDPI §8.3.5 returns payloadJws on every update). The update mints a NEW payloadUrl and a regenerated EMV payload, so it REPLACES the lost QR rather than reproducing it; host the new payloadJws at the new payloadUrl and distribute the new qrCode.

Hosting the payload is not the whole obligation: an institution serving its own domain must ALSO publish, at that domain, the key set the payer's app validates the signature against. It cannot produce that key set itself — JDPI holds the certificate and does the signing — so read it with GET /v1/indirects/{indirectId}/jwks and serve those bytes verbatim, re-reading whenever the certificate is rotated. A payload served without a matching key set fails validation at the payer, silently: the QR scans, the app fetches the document, and the payment does not go through.



## OpenAPI

````yaml /en/openapi/v3-current/pix.yaml post /v1/qrcodes/dynamic
openapi: 3.1.0
info:
  description: Brazilian PIX Direct (DICT + SPI) plugin API.
  title: plugin-br-pix-jd
  version: 1.0.0
servers: []
security:
  - BearerAuth: []
paths:
  /v1/qrcodes/dynamic:
    post:
      tags:
        - QR Codes
      summary: Create an immediate dynamic PIX QR code
      description: >-
        Generates an immediate dynamic PIX QR code and persists its conciliation
        metadata. The plugin sends the JWS host URLs (urlPayloadJson / urlJwk)
        to JDPI and self-hosts the signed JWS, so the returned QR is end-to-end
        resolvable; the response carries the resolvable payload URL the EMV
        embeds. cobv (due-date) and saque/troco variants are not supported.


        WHAT indirectId DECIDES HERE IS WHO SERVES THE QR, and it is a decision
        about hosting rather than about whose charge it is. This participant may
        serve INDIRECT participants — institutions registered with POST
        /v1/indirects. Most of them need nothing here: by default a QR raised
        for one of them is signed with THIS participant's certificate and its
        payload is hosted on THIS participant's domain, which is the ordinary
        arrangement and the one nearly every institution wants. An institution
        that has opted into holding its OWN certificate is the exception, and
        only for it does indirectId change anything: JDPI then signs with that
        institution's certificate, the payload URL is built on that
        institution's own domain, and the signed document comes back to you to
        host there. Certificate and domain are ONE decision, never two — the
        payer's app validates the signature against the certificate published at
        the domain that answered, so signing with one party's certificate while
        hosting on another's does not validate.


        ⚠️ indirectId IS SILENTLY IGNORED WHILE THIS TENANT'S
        INDIRECT-PARTICIPANTS FEATURE IS SWITCHED OFF: the value is not parsed,
        not resolved and not refused, and the QR is signed and hosted by the
        direct participant as if you had sent none. Nothing in the response says
        the routing was dropped. Naming an id and getting 404 PIX-0095 back is
        the evidence the feature is on.


        Refusals specific to indirectId, all decided before JDPI is called so a
        refused QR is never generated: 404 PIX-0095 for an id that addresses no
        institution registered in this tenant (a malformed UUID lands here too —
        it can address none); 422 PIX-0100 when the institution it names is not
        ACTIVE; 422 PIX-0113 when that institution's registered public base URL
        names a host a payer's app cannot resolve; 422 PIX-0112 when the
        composed payload URL exceeds the 77 characters BACEN allows — the path
        this participant is configured with spends most of that budget, so an
        institution's hostname must be chosen against the remaining allowance
        BEFORE it is registered, not after.


        When indirectId names an indirect that hosts its OWN certificate, the
        signed JWS comes back in payloadJws and the plugin does NOT store it —
        the indirect hosts it at payloadUrl on its own infrastructure, so THIS
        RESPONSE IS THE ONLY DELIVERY OF IT. If the response never reaches you
        (client timeout, connection reset, proxy error) the charge nevertheless
        exists at JDPI, and re-sending the same recipientConciliationId is
        refused as a duplicate (PIX-0065). Recover it, do not re-create it: call
        GET /v1/qrcodes/list with qrCodeType 12 over the registration window,
        match your own recipientConciliationId to read its documentId, then call
        PUT /v1/qrcodes/dynamic/{documentId} with the SAME indirectId — the
        update re-signs the charge and returns a fresh payloadJws (JDPI §8.3.5
        returns payloadJws on every update). The update mints a NEW payloadUrl
        and a regenerated EMV payload, so it REPLACES the lost QR rather than
        reproducing it; host the new payloadJws at the new payloadUrl and
        distribute the new qrCode.


        Hosting the payload is not the whole obligation: an institution serving
        its own domain must ALSO publish, at that domain, the key set the
        payer's app validates the signature against. It cannot produce that key
        set itself — JDPI holds the certificate and does the signing — so read
        it with GET /v1/indirects/{indirectId}/jwks and serve those bytes
        verbatim, re-reading whenever the certificate is rotated. A payload
        served without a matching key set fails validation at the payer,
        silently: the QR scans, the app fetches the document, and the payment
        does not go through.
      operationId: createDynamicQRCode
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DynamicQRBody'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QRCodeResponse'
          description: Created
        '422':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Unprocessable Entity
        '500':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Internal Server Error
        default:
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Error
components:
  schemas:
    DynamicQRBody:
      additionalProperties: false
      properties:
        accountId:
          description: The CRM account id of the recipient (sources name + city).
          examples:
            - acc-123
          type: string
        amount:
          description: Amount in centavos (an integer).
          examples:
            - 10050
          format: int64
          type: integer
        description:
          description: Optional additional-data entries (dadosAdicionais).
          items:
            $ref: '#/components/schemas/AdditionalDataBody'
          type:
            - array
            - 'null'
        expirationTime:
          description: QR expiration in seconds (0 = JDPI default).
          examples:
            - 3600
          format: int64
          type: integer
        indirectId:
          description: >-
            Optional identifier (UUID) of an indirect participant registered
            here. When that institution hosts its OWN dynamic-QR certificate,
            JDPI signs with its certificate, payloadUrl is built on its domain,
            and payloadJws is returned for it to host; otherwise the QR is
            signed and hosted by the direct participant exactly as if this were
            omitted. Omit for a direct QR. Validated server-side: unknown or
            inactive is rejected. IGNORED, without any error, while this
            tenant's indirect-participants feature is off.
          examples:
            - 3f2504e0-4f89-41d3-9a0c-0305e82c3301
          format: uuid
          type: string
        key:
          description: The recipient PIX key the dynamic QR pays into.
          examples:
            - recipient@bank.com
          type: string
        payer:
          $ref: '#/components/schemas/PayerBody'
          description: Optional payer block.
        recipientConciliationId:
          description: >-
            Conciliation id (idConciliacaoRecebedor); §8.3.2 mandatory; 26..35
            alphanumeric ([a-zA-Z0-9]); dedup gate.
          examples:
            - JDPI2020010300000000000000000000001
          type: string
        zipCode:
          description: Recipient postal code (cep).
          examples:
            - '01310100'
          type: string
      required:
        - key
        - amount
        - accountId
        - recipientConciliationId
      type: object
    QRCodeResponse:
      additionalProperties: false
      properties:
        documentId:
          description: >-
            The JDPI charge GUID (idDocumento) addressing the update leg
            (dynamic only).
          examples:
            - 52c43361-caa1-4ddb-9152-708426a25db3
          type: string
        payloadJws:
          description: >-
            The signed JWS payload, returned ONLY when the QR was generated
            under an indirect participant's own certificate — that indirect
            hosts it at payloadUrl on its own infrastructure. Absent on the
            direct path, where the plugin self-hosts it. It is returned ONCE and
            never stored: if this response is lost, do NOT re-create (the same
            recipientConciliationId is refused as a duplicate) — read the
            charge's documentId from GET /v1/qrcodes/list and re-sign it via PUT
            /v1/qrcodes/dynamic/{documentId} with the same indirectId, which
            returns a fresh payloadJws on a fresh payloadUrl.
          examples:
            - eyJhbGciOiJFUzI1NiJ9.eyJyZXYiOjB9.sig
          type: string
        payloadUrl:
          description: >-
            The resolvable JWS host URL the dynamic QR embeds (urlPayloadJson;
            schema-less; dynamic only).
          examples:
            - pix.example.com/qr/cob/fzqRwuXYSweWofLD1OX2Bw
          type: string
        qrCode:
          description: The generated EMV QR-code payload (base64-decoded, ready to render).
          examples:
            - 00020126...
          type: string
      required:
        - qrCode
      type: object
    Detail:
      additionalProperties: false
      properties:
        code:
          description: >-
            Stable, machine-readable domain error code scoped to the emitting
            service (format: <SERVICE>-NNNN).
          examples:
            - ERR-0001
          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
    AdditionalDataBody:
      additionalProperties: false
      properties:
        name:
          description: The additional-data entry name.
          examples:
            - order
          type: string
        value:
          description: The additional-data entry value.
          examples:
            - '42'
          type: string
      required:
        - name
        - value
      type: object
    PayerBody:
      additionalProperties: false
      properties:
        document:
          description: Payer document (CPF/CNPJ).
          examples:
            - '12345678909'
          type: string
        name:
          description: Payer holder name (only forwarded with a document).
          examples:
            - Jane Doe
          type: string
        validate:
          description: Whether the payer document must be validated at settlement.
          examples:
            - false
          type: boolean
      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

````