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

# Payment-order signing

> Configure the Pix plugin to sign outbound payment orders when JD requires a signed payment order: create the key and the certificate, register the certificate in JDPI Cabine, check the files, configure the plugin, confirm, and replace the key.

This page sets up payment-order signing in the Pix plugin (the rail). It is optional. You need it only if payment-order signature is enabled for your institution at JD, as defined in JD's JDPI manual (security mechanisms). Confirm this with JD. Without the signing values, nothing changes.

## Set up signing

<Steps>
  <Step title="Create the key and the certificate">
    Choose the algorithm. Use the default unless you have a reason to change it.

    | Algorithm | Key |
    | - | - |
    | `ECDSA_P256_SHA256` (default) | ECDSA on the P-256 curve |
    | `ECDSA_P384_SHA384` | ECDSA on the P-384 curve |
    | `RSA_PKCS1_SHA256` | RSA, 3072 bits or more |

    Create one key pair for your institution. It signs every payment order sent through your JD connection, including those of the indirect participants you host. A self-signed certificate is accepted. Run the block for your algorithm. Each block writes the private key to `payment-signing.key` and the certificate to `payment-signing.crt`.

    <Tabs>
      <Tab title="ECDSA P-256 (default)">
        ```bash theme={null}
        openssl ecparam -name prime256v1 -genkey -noout \
          | openssl pkcs8 -topk8 -nocrypt -out payment-signing.key
        openssl req -new -x509 -key payment-signing.key -sha256 -days 730 \
          -subj "/CN=Example Institution Pix payment signing" -out payment-signing.crt
        ```
      </Tab>

      <Tab title="ECDSA P-384">
        ```bash theme={null}
        openssl ecparam -name secp384r1 -genkey -noout \
          | openssl pkcs8 -topk8 -nocrypt -out payment-signing.key
        openssl req -new -x509 -key payment-signing.key -sha384 -days 730 \
          -subj "/CN=Example Institution Pix payment signing" -out payment-signing.crt
        ```
      </Tab>

      <Tab title="RSA 3072">
        ```bash theme={null}
        openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out payment-signing.key
        openssl req -new -x509 -key payment-signing.key -sha256 -days 730 \
          -subj "/CN=Example Institution Pix payment signing" -out payment-signing.crt
        ```
      </Tab>
    </Tabs>

    The rail reads a private key in PKCS#8, SEC 1, or PKCS#1 format. The commands above write PKCS#8. The key type must agree with the algorithm.

    Before you register the certificate, make sure that the private key is the key of the certificate:

    ```bash theme={null}
    key_pub=$(openssl pkey -in payment-signing.key -pubout) \
      && cert_pub=$(openssl x509 -in payment-signing.crt -noout -pubkey) \
      && [ -n "$key_pub" ] && [ "$key_pub" = "$cert_pub" ] \
      && echo "the key matches the certificate" \
      || echo "the key does NOT match the certificate"
    ```

    If the output is `the key does NOT match the certificate`, the key and the certificate do not agree, or a file cannot be read. Create the pair again. The rail refuses a pair that does not agree with `409 PIX-0136`, before it calls JD.
  </Step>

  <Step title="Register the certificate at JD">
    The Pix plugin signs each payment order. For JD to accept it, JD must know your certificate: register it in JDPI Cabine. Upload only the certificate, which is public. Never upload or send the private key: it goes only to the Pix plugin.

    1. In JDPI Cabine, open **Gestão de Certificados**.
    2. Click **Incluir**.
    3. In **Tipo Certificado**, select **Certificados Hash – Assinatura Payload**.
    4. Upload `payment-signing.crt`.
    5. Write down the thumbprint that JDPI Cabine shows for the certificate.

    Give the Pix plugin the same certificate in step 4. More than one certificate can be active at the same time, which lets you replace a key with no interruption. See [Replace the key](#replace-the-key).
  </Step>

  <Step title="Check the thumbprint">
    Make sure that the certificate that you give to the rail is the one registered in JDPI Cabine. Calculate its thumbprint:

    ```bash theme={null}
    openssl x509 -in payment-signing.crt -noout -fingerprint -sha1
    ```

    The output has the form `sha1 Fingerprint=40:C0:3F:...`. Remove the colons. The result must be the same as the thumbprint in JDPI Cabine. To get the value without colons directly:

    ```bash theme={null}
    openssl x509 -in payment-signing.crt -outform DER | openssl dgst -sha1 -r | cut -d' ' -f1 | tr a-f A-F
    ```
  </Step>

  <Step title="Configure the Pix plugin">
    The configuration has three values. Set the key and the certificate together, or neither. With only one of them, the rail refuses each payment to another institution with `409 PIX-0136`. A PEM value can have real line breaks, or be on one line with a literal `\n` at each line break.

    <Tabs>
      <Tab title="Self-hosted (single-tenant)">
        Set the three environment variables on the API. All three are optional. The worker does not send payment orders, so it does not need them.

        | Variable | Required | Default | Description |
        | - | - | - | - |
        | `JD_PAYMENT_SIGNING_PRIVATE_KEY` | Optional. Set it together with the certificate | — | PEM of the private key. A secret. |
        | `JD_PAYMENT_SIGNING_CERTIFICATE` | Optional. Set it together with the key | — | PEM of the certificate registered in JDPI Cabine for that key. |
        | `JD_PAYMENT_SIGNING_ALGORITHM` | Optional | `ECDSA_P256_SHA256` | `ECDSA_P256_SHA256`, `ECDSA_P384_SHA384`, or `RSA_PKCS1_SHA256`. |

        Keep the private key in a secret, never in plain configuration.

        The values take effect when the API starts.
      </Tab>

      <Tab title="Lerian-hosted">
        Give Lerian the same three values during setup: the private key, the certificate that you registered in JDPI Cabine, and the algorithm if it is not `ECDSA_P256_SHA256`. Lerian applies them when it provisions the service for your tenant. They take effect in seconds. You do not deploy or restart anything.

        Send the private key only through the secure channel that Lerian gives you for credentials during setup.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Confirm that it works">
    Send a Pix to another institution. Make sure that it settles. If the payment is refused or ends in `ERROR`, see [If something fails](#if-something-fails).
  </Step>
</Steps>

## If something fails

| What you see | Cause | What to do |
| - | - | - |
| `409 PIX-0136` | A signing value is missing or not usable. For example: only the key or only the certificate is set, the algorithm is not one of the three, the key does not agree with the algorithm, or the certificate is not the certificate of the key. | Read the message. It names the value to correct. |
| The transaction ends in `ERROR` with `JDPISPI017`, or the API answers `422 PIX-1035` | JD did not accept the signature. | Calculate the thumbprint of the configured certificate and compare it with the certificates in JDPI Cabine. A difference means that the rail signs with a certificate that JD does not know. If signing is not configured, configure it. |
| The transaction ends in `ERROR` with `JDPISPI018`, or the API answers `422 PIX-1035` | JD blocks the debits of your institution after repeated signature failures. | Correct the cause of `JDPISPI017` first. More orders do not end the block sooner. |

In each case, the rail releases the amount that it reserved, and no money moves. The rail does not send the refused order again. `409 PIX-0136` refuses only payment orders. The other JD calls, such as DICT and QR codes, continue to work.

## Replace the key

JDPI Cabine accepts more than one active certificate. Replace the key in this sequence, so that no order goes out with a certificate that JD does not know:

1. Create a new key and a new certificate.
2. Register the new certificate in JDPI Cabine. Keep the old certificate active.
3. Give the new key and the new certificate to the rail. On a Lerian-hosted deployment, give them to Lerian.
4. Wait until the change takes effect. On a self-hosted deployment, restart every running API instance, so none keeps signing with the old key. On a Lerian-hosted deployment, wait until Lerian confirms the change.
5. Send a Pix to another institution. Make sure that it settles.
6. Wait until every Pix sent before the change has a final status.
7. Delete the old certificate from JDPI Cabine.

## Related pages

* [Environment variables](/en/interfaces/pix-jd/pix-jd-environment-variables)
* [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup)
* To deploy the plugin, see the [plugin-br-pix-jd chart README](https://github.com/LerianStudio/helm/tree/main/charts/plugin-br-pix-jd).


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