Rest PKI quick reference (legacy)
The essentials of Rest PKI on one page, with links to the full articles.
Rest PKI, the cloud service at pki.rest, is a legacy product: it still receives bug and security fixes, but for a new cloud integration, use Rest PKI Core. Rest PKI Core also serves most of the APIs of the classic Rest PKI (PAdES, CAdES and XML signatures, certificate authentication and PDF marks), which eases moving an application to it.
TODO(docs): there is no guide to moving an application from Rest PKI to Rest PKI Core. Rest PKI still gets releases (1.33.9 on 2026-09-08).
What it is for
Rest PKI is a cloud service for PKI operations such as digital signatures and certificate authentication, used from virtually any programming language through client libraries; you can also host your own instance on Windows Server or Azure App Service.
In a web application it works with Web PKI: your backend starts the operation and gets a single-use token, Web PKI's signWithRestPki() signs in the browser, and your backend finishes the operation with that token.
| Choose instead | When it fits better |
|---|---|
| Rest PKI Core | You start a new cloud integration: signatures, validation, timestamps and biometric checks through a REST API, at core.pki.rest or on your own instance, with signing pages it hosts for you. |
| PKI Express | You sign on your own Windows or Linux servers from virtually any language. For Linux, the Rest PKI on-premises article recommends PKI Express instead. |
| PKI SDK | Your backend is .NET: the PKI guide recommends PKI SDK for server signatures in .NET, and it can do the server side of web signatures with Web PKI. |
| Web PKI | You need only the browser side: list the user's certificates, read them and sign with them in JavaScript. Rest PKI uses it for that step. |
Install
| Language | Package | Current major | Registry |
|---|---|---|---|
| .NET (C#, VB.NET, C++.NET) | Lacuna.RestPki.Client | 5 (latest 5.0.0); 1.24.1 for .NET Framework 3.5 to 4.6 | NuGet |
| Java 7+ | com.lacunasoftware.restpki:restpki-client | 1 (latest 1.15.11, for Java 8+; on Java 7, 1.15.7) | Maven Central |
| Java 6 | com.lacunasoftware.restpki:restpki-client-java6 | 1 (latest 1.9.0) | Maven Central |
| PHP 5.5+ | lacuna/restpki-client | 2 (latest 2.9.10) | Packagist |
| PHP 5.3 and 5.4 | lacuna/restpki-client-legacy | 1 (latest 1.1.0) | Packagist |
| Node.js | restpki-client | 2 (latest 2.3.8) | npm |
| Python | restpki-client | 1 (latest 1.3.1) | PyPI |
| Ruby | rest_pki | 1 (latest 1.1.0) | RubyGems |
- .NET has two lines of versions: 1.24.1, the last 1.x, targets .NET Framework 3.5 to 4.6 and .NET Standard 1.3 and 2.0; 2.2.0 and later target only .NET Standard 2.0, are released with Rest PKI Core and share version numbers with its client,
Lacuna.RestPkiCore.Client. Both lines work with pki.rest, so choose by target framework. See .NET. - Java:
restpki-client1.15.9 and later are compiled for Java 8; on Java 7, use 1.15.7. See Java. - PHP 5.2 has no package: use the file
RestPkiLegacy52.phpwith the Composer packageeducoder/pest. See PHP. - The REST APIs are not meant to be called directly: use a client library. API references: .NET, Java and the OpenAPI copy.
Configuration and authentication
- Access token: create an account at pki.rest, sign in and, on the Control Panel, click Generate new access token.
- Client: a
RestPkiClienttakes the endpoint and the access token, and every starter, finisher and explorer takes the client. In direct HTTP calls, send the token in the headerAuthorization: Bearer <token>. - Endpoint:
https://pki.rest/in the cloud; Web PKI calls the alternative addresshttps://restpki.lacunasoftware.com/by default, which firewalls are less likely to block. On-premises, the endpoint is the address of your instance, ending in/, and the page passes it to Web PKI'sinit()asrestPkiUrl. - Security context: each operation names a security context, which decides the trusted root CAs; in production the samples use
StandardSecurityContexts.PkiBrazil(ICP-Brasil). - Licenses: the cloud service uses no license file, and Web PKI needs no license with it, even in production. An on-premises instance needs a PKI SDK license, and Web PKI then needs its own license. See Licensing.
- Dates on PDF signatures: culture, time zone and date format come from Region and Date in your account. See Configure date and time.
var accessToken = ConfigurationManager.AppSettings["RestPkiAccessToken"];
var endpoint = ConfigurationManager.AppSettings["RestPkiEndpoint"];
if (string.IsNullOrEmpty(endpoint)) {
endpoint = "https://pki.rest/";
}
return new RestPkiClient(endpoint, accessToken);
Core operations
The code is C# from the ASP.NET MVC samples project; the other languages follow the same flow, see Samples availability.
Sign a PDF
PAdES signature with the user's certificate: PadesSignatureStarter.StartWithWebPkiAsync() returns the token, the page calls Web PKI's signWithRestPki({ token, thumbprint }), and PadesSignatureFinisher2.FinishAsync() returns the signed PDF and the signer's certificate. The token is not the access token and works once, so the sample sends no-cache headers. For the visual representation, see PAdES tags. See PAdES signature.
// GET action
var signatureStarter = new PadesSignatureStarter(Util.GetRestPkiClient()) {
SignaturePolicyId = StandardPadesSignaturePolicies.Basic,
SecurityContextId = Util.GetSecurityContextId()
};
signatureStarter.SetPdfToSign(userfilePath);
var token = await signatureStarter.StartWithWebPkiAsync();
// POST action, after signWithRestPki() in the browser
var signatureFinisher = new PadesSignatureFinisher2(Util.GetRestPkiClient()) {
Token = model.Token
};
var result = await signatureFinisher.FinishAsync();
var signerCert = result.Certificate;
Sign any file with CAdES
CMS/CAdES signature of any file, stored as .p7s: CadesSignatureStarter, then CadesSignatureFinisher2 as in the PDF flow. To co-sign, call SetCmsToCoSign() with the existing CMS instead of SetFileToSign(). See CAdES signature.
var signatureStarter = new CadesSignatureStarter(Util.GetRestPkiClient()) {
SignaturePolicyId = StandardCadesSignaturePolicies.PkiBrazil.AdrBasica,
SecurityContextId = Util.GetSecurityContextId(),
EncapsulateContent = true
};
signatureStarter.SetFileToSign(userfilePath);
var token = await signatureStarter.StartWithWebPkiAsync();
Sign an XML document
FullXmlSignatureStarter signs the whole document; XmlElementSignatureStarter with SetToSignElementId() signs one element, as in the NF-e sample. Both finish with XmlSignatureFinisher. See XML signature.
var signatureStarter = new FullXmlSignatureStarter(Util.GetRestPkiClient());
signatureStarter.SetXml(StorageMock.GetSampleXmlDocumentPath());
signatureStarter.SetSignaturePolicy(StandardXmlSignaturePolicies.XadesBes);
signatureStarter.SetSecurityContext(Util.GetSecurityContextId());
var token = await signatureStarter.StartWithWebPkiAsync();
Validate a signature
Open a signed file and validate its signatures: PadesSignatureExplorer with Validate = true, then OpenAsync(). For CAdES use CadesSignatureExplorer, for XML XmlSignatureExplorer. See Open a PAdES signature.
var sigExplorer = new PadesSignatureExplorer(Util.GetRestPkiClient()) {
Validate = true,
DefaultSignaturePolicyId = StandardPadesSignaturePolicies.Basic,
SecurityContextId = Util.GetSecurityContextId()
};
sigExplorer.SetSignatureFile(userfilePath);
var signature = await sigExplorer.OpenAsync();
Make a printer-friendly version
A PDF stamped with the signers and a verification code: upload the file with UploadFile(), validate it with PadesSignatureExplorer as above, then add marks with PdfMarker, built with the fluent PdfHelper; AlphaCode generates the code. See Printer-friendly version.
var client = Util.GetRestPkiClient();
var blob = client.UploadFile(pdfContent);
var pdfMarker = new PdfMarker(client);
pdfMarker.SetFile(blob);
pdfMarker.Marks.Add(manifestMark);
var result = pdfMarker.Apply();
Authenticate with a certificate
Certificate login: GetAuthentication(), then StartWithWebPkiAsync() with the security context; after Web PKI signs the token, CompleteWithWebPkiAsync() returns the validation results. See Authentication.
// GET action
var auth = Util.GetRestPkiClient().GetAuthentication();
var token = await auth.StartWithWebPkiAsync(Util.GetSecurityContextId());
// POST action, after signWithRestPki() in the browser
var auth = Util.GetRestPkiClient().GetAuthentication();
var validationResults = await auth.CompleteWithWebPkiAsync(model.Token);
if (!validationResults.IsValid) {
return View("Failed", validationResults);
}
Request a timestamp
ICP-Brasil timestamps with the access token as Bearer: TSP (RFC 3161) at POST https://pki.rest/tsp/a402df41-8559-47b2-a05c-be555bf66310, or REST at POST https://pki.rest/Api/TimestampPlans/a402df41-8559-47b2-a05c-be555bf66310/Issue, which returns encodedValue (the timestamp, in Base64) and info. Algorithms: SHA-1 and SHA-256. See Requesting timestamps.
{
"algorithm": "SHA256",
"value": "L80RIvFw2jwpiObzFQN+tuEQQ4E9qnGeYYYd+4DrM8M="
}
Errors
Rest PKI answers with an HTTP status: 401 when the access token is not valid, 422 with a return code when an operation fails, and 500 for an unexpected error. See Return codes.
The .NET client throws ValidationException for the error code ValidationError, whose ValidationResults say what failed, and RestPkiException for the other codes, with the code in ErrorCode. For HTTP 401 and other error statuses it throws RestErrorException, with the status in StatusCode, and when no response arrives (network failure or timeout), RestUnreachableException. All of them derive from RestException. See Errors in the .NET article. The Java client also has RestErrorException and RestUnreachableException.
| Error | What it means |
|---|---|
| HTTP 401 | The access token is not valid. |
ValidationError | The signing certificate was not valid during the signature or authentication; the validation errors tell why, such as CertificateChainRootNotTrusted. |
SecurityContextRequired | No security context was given. |
| "Could not get pending signature" (in the browser) | Web PKI could not reach Rest PKI. Check that the user's computer opens /Api/System/Info on the instance and, on-premises, the restPkiUrl. See the article. |
Test certificates and credentials
- Test certificates: PKCS #12 files with password
1234, from the Lacuna Test PKI, which must never be trusted in production. - To accept them, use the Lacuna Test PKI security context
803517ad-3bbc-4169-b085-60053a8f6dbf. The .NET samples useStandardSecurityContexts.LacunaTestin debug builds only, and warn that an on-premises installation might not have it; the other samples use it whentrustLacunaTestRoot(TRUST_LACUNA_TEST_ROOTin Python) is on in their configuration. - Access token: the PkiSuiteSamples projects come with a trial access token for pki.rest, with its expiry date in a comment next to it (in the ASP.NET MVC sample,
RestPkiAccessTokeninWeb.config). For your own application, generate a token as in Configuration and authentication.
TODO(docs): no separate test environment for pki.rest is documented.
Try it
Demos and the Rest PKI samples in each language: