# Task: Issue an e-CNPJ certificate

I want my application to do what Lacuna's "Issue an e-CNPJ certificate" demo does: Amplia issues a test e-CNPJ, with the key made on our server or in your browser.

- Docs: https://docs.lacunasoftware.com/en-us/articles/amplia
- Live demo: https://try.lacunasoftware.com/en/amplia/issue-e-cnpj-certificate
- This demo for AI agents: https://try.lacunasoftware.com/en/amplia/issue-e-cnpj-certificate.md

## Samples

- Java (spring-boot): [Issue a certificate with the key on the server using Amplia](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/IssueCertServerAmpliaController.java)
- Node.js (express): [Issue a certificate with the key on the server using Amplia](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/issue-cert-server-amplia.js)
- PHP (php): [Issue a certificate with the key on the server using Amplia](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/issue-cert-server-amplia/index.php)
- Python (flask): [Issue a certificate with the key on the server using Amplia](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/python/flask/sample/views/issue_cert_server_amplia.py)

## Call sequence

Recorded on 2026-10-12 against the real products with Lacuna's public test certificates and data. Keys, tokens, sessions, ids, file contents and personal data are masked.

### 1. PKI SDK makes an RSA 2048 key and a SHA-256 CSR on the server before the order, so a key failure costs no Amplia order.

On the server, in process: `RSA.Create(2048), then CsrGenerator.GenerateCsr(key, commonName)`

### 2. Amplia creates the e-CNPJ order, with the company and its representative in its PKI-Brazil parameters, then issues the certificate from the CSR with key media PC.

On the server: `IAmpliaService.CreateOrderAsync, then IAmpliaService.IssueCertificateAsync(orderId, csr, KeyMedia.PC)`

`POST https://amplia.lacunasoftware.com/api/orders/pki-brazil` → 200

Request:

```json
{
  "Parameters": {
    "Format": 1,
    "Name": "Julia Castro Santos",
    "EmailAddress": "someone@example.com",
    "Cnpj": "**.***.***/****-**",
    "CompanyName": "Construtora Cardoso ME:**.***.***/****-**",
    "Cpf": "***.***.***-**",
    "BirthDate": "1994-08-03T00:00:00",
    "OrganizationalUnits": [
      "Lab"
    ],
    "Organization": "Lacuna Software Demo",
    "Country": "BR"
  },
  "CAId": "00000000-0000-0000-0000-000000000000",
  "Kind": 1,
  "Validity": "365.00:00:00",
  "IssuePendingApproval": false
}
```

Response:

```json
{
  "parameters": {
    "format": "PkiBrazil",
    "name": "Julia Castro Santos",
    "emailAddress": "someone@example.com",
    "cnpj": "**.***.***/****-**",
    "companyName": "Construtora Cardoso ME:**.***.***/****-**",
    "cpf": "***.***.***-**",
    "birthDate": "1994-08-03T00:00:00",
    "organizationalUnits": [
      "Lab"
    ],
    "organization": "Lacuna Software Demo",
    "country": "BR"
  },
  "canDelete": true,
  "canEdit": true,
  "id": "00000000-0000-0000-0000-000000000000",
  "subscriptionId": "00000000-0000-0000-0000-000000000000",
  "dateCreated": "2026-10-12T02:08:02.194763+00:00",
  "caId": "00000000-0000-0000-0000-000000000000",
  "name": "Construtora Cardoso ME:**.***.***/****-** (**.***.***/****-**)",
  "alias": "Construtora Cardoso ME:**.***.***/****-** (**.***.***/****-**)",
  "certificateType": "e-CNPJ",
  "subjectIdentifier": "***",
  "subjectDisplayName": "Construtora Cardoso ME:**.***.***/****-**",
  "emailAddress": "someone@example.com",
  "status": "Pending",
  "kind": "PublicKey",
  "format": "PkiBrazil",
  "issuePendingApproval": false
}
```

`POST https://amplia.lacunasoftware.com/api/v2/certificates` → 200

Request:

```json
{
  "OrderId": "00000000-0000-0000-0000-000000000000",
  "Csr": "<Csr, 944 bytes>",
  "KeyMedia": 1
}
```

Response:

```json
{
  "parameters": {
    "format": "PkiBrazil",
    "name": "JULIA CASTRO SANTOS",
    "emailAddress": "someone@example.com",
    "cnpj": "**.***.***/****-**",
    "companyName": "CONSTRUTORA CARDOSO ME",
    "cpf": "***.***.***-**",
    "birthDate": "1994-08-03T00:00:00",
    "organizationalUnits": [
      "Lab"
    ],
    "organization": "Lacuna Software Demo",
    "country": "BR"
  },
  "info": {
    "subjectName": {
      "country": "BR",
      "organization": "Lacuna Software Demo",
      "organizationUnit": "Lab",
      "commonName": "CONSTRUTORA CARDOSO ME:**.***.***/****-**",
      "allValues": {
        "2.5.4.6": [
          "BR"
        ],
        "2.5.4.10": [
          "Lacuna Software Demo"
        ],
        "2.5.4.11": [
          "Lab"
        ],
        "2.5.4.3": [
          "CONSTRUTORA CARDOSO ME:**.***.***/****-**"
        ]
      },
      "organizationalUnits": [
        "Lab"
      ],
      "dnString": "CN=CONSTRUTORA CARDOSO ME:**.***.***/****-**,OU=Lab,O=Lacuna Software Demo,C=BR"
    },
    "emailAddress": "someone@example.com",
    "issuerName": {
      "country": "BR",
      "organization": "Lacuna Software",
      "organizationUnit": "IT",
      "commonName": "Lacuna CA Test v7",
      "allValues": {
        "2.5.4.6": [
          "BR"
        ],
        "2.5.4.10": [
          "Lacuna Software"
        ],
        "2.5.4.11": [
          "IT"
        ],
        "2.5.4.3": [
          "Lacuna CA Test v7"
        ]
      },
      "organizationalUnits": [
        "IT"
      ],
      "dnString": "CN=Lacuna CA Test v7,OU=IT,O=Lacuna Software,C=BR"
    },
    "serialNumber": "<hex, 19 bytes>",
    "validityStart": "2026-10-12T02:03:02+00:00",
    "validityEnd": "2027-10-12T02:08:02+00:00",
    "crlDistributionPoints": [
      "http://ca.lacunasoftware.com/crls/lacuna-ca-test-v7.crl",
      "http://ca.lacunasoftware.com.br/crls/lacuna-ca-test-v7.crl"
    ],
    "ocspUris": [],
    "isSelfSigned": false,
    "isCA": false
  },
  "content": "<content, 1681 bytes>",
  "hasSignedAgreement": false,
  "id": "00000000-0000-0000-0000-000000000000",
  "subscriptionId": "00000000-0000-0000-0000-000000000000",
  "caId": "00000000-0000-0000-0000-000000000000",
  "dateIssued": "2026-10-12T02:08:02.739533+00:00",
  "dateEffective": "2026-10-12T02:03:02+00:00",
  "dateExpires": "2027-10-12T02:08:02+00:00",
  "alias": "Construtora Cardoso ME:**.***.***/****-** (**.***.***/****-**)",
  "subjectDisplayName": "CONSTRUTORA CARDOSO ME:**.***.***/****-**",
  "serialNumber": "<hex, 19 bytes>",
  "isCA": false,
  "kind": "PublicKey",
  "format": "PkiBrazil",
  "isPendingApproval": false
}
```

### 3. PKI SDK puts the key and the issued certificate in a PKCS#12 with no password, kept in the server's memory for the .pfx download.

On the server, in process: `Pkcs12Generator.Generate(key, certificate, alias, password)`

## Patterns to copy

- Make the key where it will live. On the server, PKI SDK makes it, you tell Amplia `KeyMedia.PC` and hand back a PKCS#12; in the browser, Web PKI makes it and only the CSR reaches your server, with `KeyMedia.PC` for the computer and `KeyMedia.CryptoDevice` for a token.
- Issuing is two Amplia calls, `CreateOrderAsync` then `IssueCertificateAsync(orderId, csr, keyMedia)`: make the key and CSR before creating the order, so a key failure doesn't use up an order.
- Amplia takes the certificate's subject from the order's `PkiBrazilCertificateParameters`, never from the CSR: put the identity there, the CNPJ and CPF without their masks and names without diacritics.
- With a browser key, Web PKI returns the key's id with the CSR: pass it back to `importCertificate` (or `importTokenCertificate`) once the certificate is issued, to install it beside its key.
- Load the PKI SDK licence with `PkiConfig.LoadLicense(byte[])` (the string overload takes a file path), and pass `""`, not null, to `Pkcs12Generator.Generate` for a PKCS#12 with no password.

## What to do

Implement this in my project with its existing stack, language, framework and conventions, following the call sequence and the patterns above, and adapting the samples rather than copying them whole. Ask me before adding any dependency or package. Keep API keys and private keys out of the browser and out of the repository.
