---
title: "Create certificate orders"
description: "How to create Amplia certificate orders through the API: endpoints by certificate format, common fields, ICP-Brasil (e-CPF, e-CNPJ) and SSL/TLS parameters, and reading, updating or deleting orders."
canonical: "https://docs.lacunasoftware.com/en-us/articles/amplia/integration/orders"
locale: "en"
product: "Amplia"
last_updated: "2026-10-12"
---

# Create certificate orders

Every certificate that [Amplia](https://docs.lacunasoftware.com/en-us/articles/amplia) issues starts with an order: it names the CA that issues the certificate and holds the
certificate's validity and the holder's data. 
An order yields one certificate: once it is issued, the order's `status` is `Issued` and its `certificateId` points at the certificate. 
See [Before you start](https://docs.lacunasoftware.com/en-us/articles/amplia/integration#before-you-start) for the API key, the endpoint and the CA id.

## Endpoints by certificate format

Each certificate format has its own endpoint, `POST /api/orders/{format}`, whose body takes the common fields below plus a `parameters`
object of that format: 

| Format | Endpoint | `parameters` |
|---|---|---|
| ICP-Brasil (e-CPF, e-CNPJ) | `POST /api/orders/pki-brazil` | `PkiBrazilCertificateParameters` |
| SSL/TLS | `POST /api/orders/ssl` | `SslCertificateParameters` |
| Brazilian student ID card (CIE), an attribute certificate | `POST /api/orders/cie` | `CieCertificateParameters` |
| PrivateID, an attribute certificate | `POST /api/orders/private-id` | `PrivateIDCertificateParameters` |
| Paraguay | `POST /api/orders/pki-paraguay` | `PkiParaguayCertificateParameters` |
| Ecuador | `POST /api/orders/bce` | `EcuadorBceCertificateParameters` |
| Cabo Verde | `POST /api/orders/pki-cabo-verde` | `PkiCaboVerdeCertificateParameters` |
| Custom profile | `POST /api/orders/custom` | `CustomCertificateParameters` |

The API also has `POST /api/orders/latinus` and `POST /api/orders/br-laboral`, and a generic `POST /api/v2/orders` whose `parameters` can
be of any format. 
TODO(docs): what the Latinus and BRLaboral formats are for.

The client libraries choose the endpoint from the class of the `parameters` object. All four create ICP-Brasil, SSL/TLS and CIE orders;
the Node.js client also creates Paraguay orders, and the Java client Latinus orders. They also send CNB and ARISP orders (and the Java
and PHP clients CNB CA orders) to `api/orders/cnb`, `api/orders/arisp` and `api/orders/cnb-ca`, which the OpenAPI description doesn't
list. 
Amplia 5.0.1 serves these three endpoints, with `CnbCertificateParameters`, `CnbCACertificateParameters` and
`ArispCertificateParameters`. 
TODO(docs): the parameters of CNB, CNB CA and ARISP orders (see [Colégio Notarial do Brasil - ASN.1 types](https://docs.lacunasoftware.com/en-us/articles/asn1-cnb) and [ARISP - ASN.1 types](https://docs.lacunasoftware.com/en-us/articles/asn1-arisp) for those certificates).

## Common fields

| Field | Meaning |
|---|---|
| `caId` | Id of the CA that issues the certificate. |
| `templateId` | Id of the template (certificate profile) to apply. |
| `kind` | `PublicKey` or `Attribute`. |
| `parameters` | The holder's data, in the format of the endpoint. Required. |
| `validityEnd`, `validityStart` | Dates the certificate is valid until and from. |
| `validity` | Validity as a time span: the recorded demo calls send `"365.00:00:00"` for a year and `"90.00:00:00"` for 90 days. |
| `digestAlgorithm` | `SHA1`, `SHA256`, `SHA384` or `SHA512`. |
| `serialNumber` | A predefined serial number for the certificate. |
| `policyOid`, `policyStatementUrl`, `policyUserNotices`, `policies` | Certificate policies to include. |
| `issuePendingApproval` | Boolean; the recorded demo calls send `false`. |

* The Node.js and Python samples send `validityEnd` as a date in the `MM-DD-YYYY` pattern, two years from the current date. 
* An order with no validity, on a template that has no default validity, is rejected. 
* The client libraries send only `caId`, `templateId`, `kind`, `parameters`, `validityEnd` and a field for copying from a certificate;
  to set the other fields, call the API directly. The Java client formats `validityEnd` as `MM-dd-yyyy`. 
* TODO(docs): what `issuePendingApproval` and `copyFromCertificate` do, and how a certificate pending approval is approved (`POST /api/certificates/{id}/approval`).

## ICP-Brasil certificates (e-CPF and e-CNPJ)

`PkiBrazilCertificateParameters` requires `name` and `cpf`. The other fields include `emailAddress`, `birthDate`, `phoneNumber`, `cnpj`
and `companyName` for an e-CNPJ, the RG and OAB numbers, `nis`, `cei`, `organization`, `organizationalUnits` and `country`. 

* `phoneNumber` is needed when the holder issues the certificate on Amplia's issue page, which texts them a confirmation code. 
* Amplia takes the certificate's subject from these parameters, never from a CSR: put the identity here, with the CPF and CNPJ without
  their masks and names without diacritics. 
* `normalizeCommonName` and `appendIdentifierToCommonName` normalize the Common Name (CN=) and add the CPF or CNPJ to it. 
* In the recorded demo calls, an order with a CPF comes back with `certificateType` `e-CPF`, and one that also has `cnpj` and
  `companyName` comes back as `e-CNPJ`. 
* The Node.js, PHP and Python clients send the organizational units as `organizationUnits`, while the API's field is
  `organizationalUnits`; the Java client uses the API's name. 

The samples create an e-CPF order with the name and CPF only: 

**Node.js**

```js
const {PkiBrazilCertificateParameters, CreateOrderRequest, CertificateKinds} = require('amplia-client');

const CONFIG = Config.getInstance().get('amplia');
const client = Util.getAmpliaClient();
const request = new CreateOrderRequest({
	caId: CONFIG['caId'],
	validityEnd: Util.getTwoYearsFromNowDate(),
	kind: CertificateKinds.PUBLIC_KEY,
	parameters: new PkiBrazilCertificateParameters({
		name: req.body.subjectName,
		cpf: req.body.cpf
	})
});
let order = await client.createOrder(request);
```

**Java**

```java
AmpliaClient client = Util.getAmpliaClient();
CreateOrderRequest<PkiBrazilCertificateParameters> createOrderRequest = new CreateOrderRequest<>();
createOrderRequest.setCAId(ApplicationProperties.getInstance().getAmplia().getCaId());
createOrderRequest.setValidityEnd(Util.getDateYearsFromNow(2));
createOrderRequest.setKind(CertificateKinds.PUBLIC_KEY);
PkiBrazilCertificateParameters parameters = new PkiBrazilCertificateParameters();
parameters.setName(request.getSubjectName());
parameters.setCpf(request.getCpf());
createOrderRequest.setParameters(parameters);
Order order = client.createOrder(createOrderRequest);
```

**PHP**

```php
use Lacuna\Amplia\CreateOrderRequest;
use Lacuna\Amplia\CertificateKinds;
use Lacuna\Amplia\PkiBrazilCertificateParameters;

$client = Util::getAmpliaClient();
$createOrderRequest = new CreateOrderRequest();
$createOrderRequest->caId = getConfig()['amplia']['caId'];
$createOrderRequest->validityEnd = Util::getDateYearsFromNow(2);
$createOrderRequest->kind = CertificateKinds::PUBLIC_KEY;
$parameters = new PkiBrazilCertificateParameters();
$parameters->name = $subjectName;
$parameters->cpf = $cpf;
$createOrderRequest->parameters = $parameters;
$order = $client->createOrder($createOrderRequest);
```

**Python**

```python
from amplia_client import CreateOrderRequest, CertificateKinds, PkiBrazilCertificateParameters

client = get_amplia_client()
req = CreateOrderRequest()
req.ca_id = current_app.config['AMPLIA_CA_ID']
req.validity_end = get_two_years_from_now_date()
req.kind = CertificateKinds.PUBLIC_KEY
parameters = PkiBrazilCertificateParameters()
parameters.name = request.form['subjectName']
parameters.cpf = request.form['cpf']
req.parameters = parameters
order = client.create_order(req)
```

Over HTTP, the e-CPF demo sends this body to `POST /api/orders/pki-brazil` (personal data masked). Its client serializes enums as
numbers (`"Format": 1`, `"Kind": 1`), while the response names them (`"format": "PkiBrazil"`, `"kind": "PublicKey"`): 

```json
{
  "Parameters": {
    "Format": 1,
    "Name": "(DEMO) Diego Rocha Gomes",
    "EmailAddress": "someone@example.com",
    "Cpf": "***.***.***-**",
    "BirthDate": "1988-12-06T00:00:00",
    "OrganizationalUnits": [
      "Lab"
    ],
    "Organization": "Lacuna Software Demo",
    "Country": "BR",
    "PhoneNumber": "+55 ** *****-****"
  },
  "CAId": "00000000-0000-0000-0000-000000000000",
  "Kind": 1,
  "Validity": "365.00:00:00",
  "IssuePendingApproval": false
}
```

## SSL/TLS certificates

`SslCertificateParameters` holds `dnsNames`, `subjectName`, `keyUsages`, `extendedKeyUsages`, `qualifiedStatements` and
`organizationIdentifier`.  Amplia's SSL/TLS certificates follow the
CA/Browser Forum guidelines and accept wildcard names and IP addresses besides regular DNS names. 

The DNS names and the subject come from the order, never from the CSR: the SSL/TLS demo sets the DNS names, the subject, the key usages
`DigitalSignature` and `KeyEncipherment` and the extended key usage `ServerAuth` explicitly. It sends this body to
`POST /api/orders/ssl`, then [issues the certificate from a CSR](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/issue-from-csr): 

```json
{
  "Parameters": {
    "Format": 2,
    "DnsNames": [
      "www.example.com"
    ],
    "SubjectName": {
      "Organization": "Lacuna Software Demo",
      "CommonName": "www.example.com",
      "OrganizationalUnits": [
        "Lab"
      ]
    },
    "KeyUsages": [
      3,
      7
    ],
    "ExtendedKeyUsages": [
      1
    ]
  },
  "CAId": "00000000-0000-0000-0000-000000000000",
  "Kind": 1,
  "Validity": "90.00:00:00",
  "IssuePendingApproval": false
}
```

The demo checks the DNS names before calling Amplia (1 to 10 names, lowercased, `*` only as the whole leftmost label, no IP addresses),
and maps Amplia's `BadDnsName` and `BadCsr` error codes to messages of its own. 
These are the demo's own limits: Amplia itself accepts IP addresses. 
The Node.js and PHP clients' `SslCertificateParameters` only set `dnsNames`. 

## Read, update and delete orders

| Operation | Endpoint |
|---|---|
| Read an order | `GET /api/orders/{id}`; `GET /api/v2/orders/{id}` also returns its `parameters` |
| Read an order with its format's parameters | `GET /api/orders/{format}/{id}`, for example `GET /api/orders/pki-brazil/{id}` |
| Update an order | `PUT /api/orders/{format}/{id}` |
| Delete an order | `DELETE /api/orders/{id}` |
| List orders | `GET /api/orders`, with `Q`, `Limit`, `Offset`, `Cursor` and `Order` (`Asc`, `Desc`) |

* An order's `status` is `Pending`, `Locked` or `Issued`, and `canEdit` and `canDelete` tell whether it can still be changed or
  deleted; an issued order cannot be deleted. 
* `keyMediaConstraints` lists the [key media](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/issue-from-csr#key-media) the order can be issued on. 
* Blocked orders can be viewed and unlocked on the dashboard, and `PUT /api/orders/{id}/unlock-request` exists in the API. 
  TODO(docs): what locks an order and what the unlock request does.

## Next steps

* [Issue on the holder's machine](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/issue-on-user-machine)
* [Issue from a CSR](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/issue-from-csr)
* [Issue a PKCS #12 file](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/pkcs12)
* [Attribute certificates](https://docs.lacunasoftware.com/en-us/articles/amplia/integration/attribute-certificates)
