Get started on integration - Rest PKI Core
This article takes you from nothing to a first working call to Rest PKI Core. You will:
- Get your credentials: the endpoint of the instance and an API key
- Set up the client library for your programming language, or call the REST API directly
- Make a first call to check that everything is in place
How the integration works
Your application talks to Rest PKI Core through a REST API, authenticated by an API key. The calls are always made by your application's backend: the API key gives access to your subscription, so it must never reach a browser or a mobile app.
When an operation needs the user, such as choosing a certificate and signing a document, or taking a selfie for a biometric check, you don't have to build those pages. Your backend creates a session, Rest PKI Core returns a URL, and the user is sent to a page hosted by Rest PKI Core. When the user is done, they come back to your application, which fetches the results through the API. See signature sessions and biometric sessions.
Get your credentials
You need two parameters:
| Parameter | Description |
|---|---|
| Endpoint | Address of the Rest PKI Core instance. On the SaaS instance it is https://core.pki.rest/. On your own instance, it is the address of its dashboard, such as https://restpki.yourcompany.com/ |
| API key | Key that identifies your application and authenticates its calls. It looks like MyApp|0f3c…: a prefix taken from the application name, a |, then 64 hexadecimal characters |
If you are using the SaaS instance and your organization does not have access to it yet, contact our developer support. If you are using your own on-premises instance and have no subscription to work with yet, see Creating a subscription.
There is no public sandbox. The samples and the demo site use a trial subscription on the SaaS instance, whose API key Lacuna rotates every month: take the current key from the samples repository instead of copying it into your code.
Create an API key
API keys belong to applications. Once you can sign in to the dashboard, create an application for your system and a key for it:
- Sign in to the dashboard of the instance
- On the left menu, click Applications, then Add
- On New Application, fill in a Name for the application. If you are asked for a Subscription, choose the one your system will work on
- Under Roles, check Worker (see Choosing roles below)
- Click Create
- On the application's page, click Keys, then Add
- On New Application Key, fill in a Description (for instance, the environment that will use the key) and choose an Expiration (see Key expiration below), then click Create
- Copy the key shown on the Key created dialog and store it in a safe place. You will not be able to view it again: if you lose it, create a new key
Anyone who has the key can act on your subscription with the roles of its application. Store it as you would store a password: in a secret store such as Azure Key Vault, in an environment variable or, during development, in .NET user secrets. Never commit it to source control and never send it to a browser or a mobile app.
Choosing roles
The roles of an application define what its keys can do. Give your application only the roles it needs:
| Role | What it allows |
|---|---|
| Worker | The operations of an integration: create and use signature sessions, sign documents, inspect signatures, authenticate users with certificates, issue timestamps, run biometric sessions, add marks and stamps to documents, and view transactions. This is the role most integrations need |
| Monitor | View transactions, biometric sessions, enrollment batches and invoices, without performing any operation |
| Manager | Everything a Worker does, plus managing the subscription's settings and security contexts. It can view applications and users, but not manage them |
| Admin | Everything, including managing applications and users |
Key expiration
The Expiration of a key can be In 1 year, In 2 years or Never expires. When a key expires, the calls made with it start failing with HTTP 401, so if you choose an expiring key, plan its replacement: an application can have more than one key, which lets you create the new key and switch your system to it before the old one expires.
Choose how to call the API
Rest PKI Core's APIs are plain REST with JSON, but you don't need to deal with HTTP yourself. Lacuna provides client libraries that wrap the API in the idioms of each language, together with sample projects that use them:
| Language | Package | Source code | Samples |
|---|---|---|---|
| .NET | Lacuna.RestPkiCore.Client on NuGet | — | PkiSuiteSamples/dotnet |
| PHP | lacuna/restpkicore-client on Packagist | GitHub | PkiSuiteSamples/php |
| Java | com.lacunasoftware.restpki:restpkicore-client on Maven Central | GitHub | PkiSuiteSamples/java |
| Node.js | restpki-core-client on npm | GitHub | PkiSuiteSamples/nodejs |
| Python | restpki-ng-python-client on PyPI | — | PkiSuiteSamples/python |
Jump to the section of your language:
For any other language, call the API directly.
.NET
Add the NuGet package Lacuna.RestPkiCore.Client to your project:
dotnet add package Lacuna.RestPkiCore.Client
The package targets .NET Standard 2.0, so it runs on .NET 5 or later, on .NET Core 2.0 or later and on .NET Framework 4.6.1 or later (Microsoft recommends 4.7.2 or later for .NET Standard 2.0 libraries).
The package is named Lacuna.RestPkiCore.Client, but its classes are in the Lacuna.RestPki.Client namespace.
ASP.NET Core applications
Register the Rest PKI Core services in Program.cs, binding their options to the RestPki configuration section:
builder.Services.AddRestPki().Configure(builder.Configuration.GetSection("RestPki"));
Then add the section to appsettings.json, leaving the API key out of it:
{
"RestPki": {
"Endpoint": "https://core.pki.rest/"
}
}
Provide the API key through a source that stays out of source control. During development, use user secrets:
dotnet user-secrets set "RestPki:ApiKey" "YOUR_API_KEY"
In production, set the environment variable RestPki__ApiKey, or use a secret store such as Azure Key Vault. ASP.NET Core merges these
sources into the same RestPki section.
Wherever your application needs to call Rest PKI Core, request an IRestPkiService through dependency injection:
using Lacuna.RestPki.Client;
public class SignatureController : Controller {
private readonly IRestPkiService restPkiService;
public SignatureController(IRestPkiService restPkiService) {
this.restPkiService = restPkiService;
}
...
}
AddRestPki() also registers IRestBioService, the service used for biometric sessions.
If you prefer to set the options in code, pass them to AddRestPki():
builder.Services.AddRestPki(options => { options.Endpoint = ...; options.ApiKey = ...; });
Other .NET applications
If your application does not use ASP.NET Core dependency injection, as in a .NET Framework or console application, get an IRestPkiService
from the static class RestPkiServiceFactory:
using Lacuna.RestPki.Client;
var restPkiService = RestPkiServiceFactory.GetService(new RestPkiOptions() {
Endpoint = ConfigurationManager.AppSettings["RestPkiEndpoint"],
ApiKey = ConfigurationManager.AppSettings["RestPkiApiKey"],
});
In this example, the parameters come from the appSettings section of the web.config or app.config file, but they can come from wherever
you prefer. For biometric sessions, use RestPkiServiceFactory.GetBioService(), which takes the same parameters.
Each call to the factory creates a new HTTP client, so create the service once and reuse it, for instance in a static field, instead of creating one on every request.
Options
RestPkiOptions has the following properties, which can also be set in the RestPki configuration section:
| Property | Description |
|---|---|
Endpoint | Address of the Rest PKI Core instance. If the address has a path, end it with a slash (https://yourcompany.com/restpki/), otherwise the last segment of the path is dropped |
ApiKey | The application's API key |
CultureName | Culture of the API's responses, such as en-US, pt-BR or es-ES (see Culture below). Also available as Culture, of type CultureInfo |
TimeoutSeconds | How long to wait for each response, in seconds. If not set, the client waits 60 seconds. Also available as Timeout, of type TimeSpan |
Culture
The client tells Rest PKI Core which culture to use in each call, and by default it uses the culture of the current thread
(Thread.CurrentThread.CurrentUICulture). This works well when your application sets the culture of each request, as ASP.NET Core does with
request localization.
To always use the same culture regardless of the thread, set CultureName. In ASP.NET Core, add it to the configuration section:
{
"RestPki": {
"Endpoint": "https://core.pki.rest/",
"CultureName": "en-US"
}
}
Otherwise, set it on RestPkiOptions:
var restPkiService = RestPkiServiceFactory.GetService(new RestPkiOptions() {
...,
CultureName = "en-US",
});
The same setting defines the language of the hosted biometric capture page (taken from the Accept-Language of the session-start request), so setting CultureName pins every capture page to that language.
Errors
The methods of IRestPkiService may throw the following exceptions:
| Exception | When |
|---|---|
RestPkiExceptionV2 | The API rejected the request (HTTP 422). Check the ErrorCode property, of type ErrorCodesV2, against the error codes. The ErrorMessage property describes the error in English and is meant for your logs, not for your users |
ValidationException | A certificate or signature failed validation. The ValidationResults property tells what failed |
RestForbiddenOperationException | The application doesn't have a role that allows the operation (HTTP 403, see Choosing roles) |
RestErrorException | Any other HTTP error, such as 401 for a missing or invalid API key. The StatusCode property has the HTTP status code (see HTTP status codes) |
RestUnreachableException | The endpoint could not be reached: check the endpoint address and your network |
TimeoutException | The response took longer than TimeoutSeconds |
RestPkiExceptionV2 and ValidationException are in the Lacuna.RestPki.Client namespace, and the other Rest…Exception classes are in
the Lacuna.RestClient namespace. All of them derive from Lacuna.RestClient.RestException, so to handle any error from the API in a
single place, catch RestException (and TimeoutException, which is a standard .NET exception).
PHP
Add the Composer package lacuna/restpkicore-client to your project (if you don't have Composer yet, get it here):
composer require lacuna/restpkicore-client
The package requires PHP 5.5 or later and uses Guzzle 6 or 7 to make HTTP calls. It is open source, hosted on GitHub: feel free to fork it if you need to customize it.
Create a RestPkiService, which implements RestPkiServiceInterface, passing it a RestPkiCoreClient built with the endpoint and the
API key:
use Lacuna\RestPki\RestPkiOptions;
use Lacuna\RestPki\RestPkiCoreClient;
use Lacuna\RestPki\RestPkiService;
$options = new RestPkiOptions('https://core.pki.rest/', getenv('RESTPKI_API_KEY'));
$client = new RestPkiCoreClient($options);
$service = new RestPkiService($client);
In this example, the API key comes from the environment variable RESTPKI_API_KEY, which keeps it out of your code.
Culture
To set the culture of the API's responses, pass it as the third parameter of RestPkiOptions:
$options = new RestPkiOptions('https://core.pki.rest/', getenv('RESTPKI_API_KEY'), 'en-US');
Errors
All of the following exceptions are in the Lacuna\RestPki namespace:
| Exception | When |
|---|---|
RestPkiException | The API rejected the request (HTTP 422). getErrorCode() returns the error code and getDetail() describes the error, for your logs |
ValidationException | A certificate or signature failed validation |
RestErrorException | Any other HTTP error. getStatusCode() returns the HTTP status code (see HTTP status codes) |
RestUnreachableException | The endpoint could not be reached |
PHP samples
In our samples repository, the folders whose names end
in -rest-core use Rest PKI Core. The endpoint and the API key are set in the restPkiNg entry of
config.php.
Java
Add the package com.lacunasoftware.restpki:restpkicore-client, from Maven Central, to your project. It requires Java 8 or later.
With Gradle, in build.gradle:
repositories {
mavenCentral()
}
dependencies {
implementation 'com.lacunasoftware.restpki:restpkicore-client:1.4.0'
}
With Maven, in pom.xml:
<dependency>
<groupId>com.lacunasoftware.restpki</groupId>
<artifactId>restpkicore-client</artifactId>
<version>1.4.0</version>
</dependency>
Check Maven Central for the latest version.
Don't confuse it with com.lacunasoftware.restpki:restpki-core-client, an older package that is no longer updated.
The package is open source, hosted on GitHub: feel free to fork it if you need to customize it.
Get a RestPkiService from RestPkiServiceFactory.getService(), passing a RestPkiOptions with the endpoint and the API key:
import com.lacunasoftware.restpkicore.RestPkiOptions;
import com.lacunasoftware.restpkicore.RestPkiService;
import com.lacunasoftware.restpkicore.RestPkiServiceFactory;
RestPkiOptions options = new RestPkiOptions();
options.setEndpoint("https://core.pki.rest/");
options.setApiKey(System.getenv("RESTPKI_API_KEY"));
RestPkiService service = RestPkiServiceFactory.getService(options);
In this example, the API key comes from the environment variable RESTPKI_API_KEY, which keeps it out of your code. If your application
reaches the internet through a proxy, set it with options.setProxy().
Culture
To set the culture of the API's responses, call setCulture():
options.setCulture("en-US");
Errors
The methods of RestPkiService declare throws Exception. These are the exceptions they throw, all in the com.lacunasoftware.restpkicore
package:
| Exception | When |
|---|---|
RestPkiException | The API rejected the request (HTTP 422). getErrorCode() returns the error code |
ValidationException | A certificate or signature failed validation |
RestResourceNotFoundException | The resource was not found (HTTP 404) |
RestErrorException | Any other HTTP error. getStatusCode() returns the HTTP status code (see HTTP status codes) |
RestUnreachableException | The endpoint could not be reached |
Java samples
In our samples repository, the controllers whose names
end in CoreController, such as SignatureSessionRestCoreController, use Rest PKI Core. The endpoint and the API key are set under
rest-pki-core in application.yml.
Node.js
Add the package restpki-core-client, from npm, to your project:
npm install restpki-core-client
The package doesn't declare the Node.js versions it supports. It brings its TypeScript typings, and makes its HTTP calls with the request
package, which is deprecated on npm. It is open source, hosted on GitHub.
Create a RestPkiCoreClient, passing it the endpoint, without the trailing slash, as baseUrl and the API key as apiKey:
const { RestPkiCoreClient } = require('restpki-core-client');
const client = new RestPkiCoreClient({
baseUrl: 'https://core.pki.rest',
apiKey: process.env.RESTPKI_API_KEY,
});
In this example, the API key comes from the environment variable RESTPKI_API_KEY, which keeps it out of your code. The library sends it on
the X-Api-Key header and builds each URL by appending the route, such as /api/signature, to baseUrl.
The client has a method for each route, such as prepareSignature() for POST api/signature, completeSignature() for
POST api/signature/completion and createSignatureSession() for POST api/signature-sessions. Each method returns a promise of an object
whose data property holds the body of the response, and statusCode its HTTP status code:
const response = await client.createSignatureSession({
returnUrl: 'https://localhost:3000/signature-callback',
});
// Send the user to response.data.redirectUrl
The examples in the package's README create a Configuration object, a class that version 1.0.2 doesn't have: create a RestPkiCoreClient
as above. The timeout and ignoreSslErrors options, which RestPkiCoreClient accepts, have no effect in this version.
Culture
The library sends no Accept-Language header. To set the culture of the API's responses, add it to customHeaders, which the library sends
on every request:
const client = new RestPkiCoreClient({
baseUrl: 'https://core.pki.rest',
apiKey: process.env.RESTPKI_API_KEY,
customHeaders: { 'Accept-Language': 'en-US' },
});
Errors
When the API answers with an HTTP status code other than 2xx, the promise is rejected with an HttpError, exported by the package, whose
statusCode property holds the HTTP status code (see HTTP status codes) and body the body of the response, already
parsed from JSON. On HTTP 422, when the API rejected the request, body is an ErrorModel. When the endpoint can't be reached,
the promise is rejected with the error of the request package.
Node.js samples
In our samples repository, the routes whose files end
in -core.js, such as pades-signature-core.js, use Rest PKI Core: they sign PDFs with two-step signatures and add
PDF stamps. The endpoint and the API key are set under restPkiCore in config/default.js.
Python
Add the package restpki-ng-python-client, from PyPI, to your project:
pip install restpki-ng-python-client
The package doesn't declare the Python versions it supports. It depends on pydantic 2 and on urllib3 below 2.1. Don't install its pre-releases
(pip install --pre): 0.9.2rc1 doesn't contain the library.
The package is named restpki-ng-python-client, but you import it as restpki_ng_python_client.
The library is generated from the API: there is a class for each group of routes, such as SignatureApi, SignatureSessionsApi,
DocumentsApi, SignatureInspectionApi and PdfApi, and a method for each route, named after it, such as api_signature_post() for
POST api/signature. Create an ApiClient with the endpoint, without the trailing slash, and send the API key on the X-Api-Key header:
import os
import certifi
from restpki_ng_python_client import ApiClient, Configuration, SignatureApi
configuration = Configuration(host='https://core.pki.rest', ssl_ca_cert=certifi.where())
client = ApiClient(configuration)
client.set_default_header('X-Api-Key', os.environ['RESTPKI_API_KEY'])
signature_api = SignatureApi(client)
In this example, the API key comes from the environment variable RESTPKI_API_KEY, which keeps it out of your code, and the trusted CAs for HTTPS
come from the certifi package. The library builds each URL by appending the route to host, so an endpoint
ending in / gives URLs with //.
Don't use the RestPkiClient class of version 0.9.1.1: it turns off the verification of the server's TLS certificate.
Culture
The library sends no Accept-Language header. To set the culture of the API's responses, add it as a default header:
client.set_default_header('Accept-Language', 'en-US')
Errors
All of the following exceptions are in the restpki_ng_python_client.exceptions module, and derive from ApiException:
| Exception | When |
|---|---|
BadRequestException | HTTP 400: the request is malformed |
UnauthorizedException | HTTP 401: the API key is missing, invalid or expired |
ForbiddenException | HTTP 403: the application doesn't have a role that allows the operation (see Choosing roles) |
NotFoundException | HTTP 404 |
ServiceException | HTTP 500 or other 5xx |
ApiException | Any other HTTP error, including 422, when the API rejected the request. The library doesn't parse the ErrorModel: read it as JSON from the body property, and the HTTP status code from status |
Python samples
In our samples repository, the view
pades_signature_rest_core.py uses Rest PKI Core, to sign a PDF with two-step signatures. The endpoint and the API key are set in REST_PKI_CORE_ENDPOINT and
REST_PKI_CORE_API_KEY, in sample/config.py.
Calling the API directly
The APIs of Rest PKI Core are RESTful, receiving and returning JSON, so they are easy to call from any modern programming language. If your application uses a language without a client library, call them directly:
- URL: append the API's relative path to the endpoint. For instance,
api/signature-sessionson the SaaS instance ishttps://core.pki.rest/api/signature-sessions - Authentication: pass the API key on the
X-Api-Keyheader of every request - Body: send JSON with the
Content-Type: application/jsonheader
For instance:
POST https://core.pki.rest/api/signature-sessions
X-Api-Key: MyApp|0f3c...
Content-Type: application/json
All the APIs, with their requests and responses, are described on the API reference. On your own instance,
the reference is at the path swagger of the endpoint, such as https://restpki.yourcompany.com/swagger.
HTTP status codes
The API responds with the following HTTP status codes:
| Code | Meaning |
|---|---|
| 200 (OK) | The request succeeded. The response depends on the API: see the API reference |
| 400 (Bad Request) | The request is malformed, for instance, a required field is missing |
| 401 (Unauthorized) | The API key is missing, invalid or expired |
| 403 (Forbidden) | The API key is valid, but its application doesn't have a role that allows the operation (see Choosing roles) |
| 422 (Unprocessable Entity) | The API rejected the request, usually because of a parameter that must be fixed. The body is an ErrorModel |
| 500 (Internal Server Error) | An unexpected error happened. The exceptionCode field of the body helps diagnose the problem: include it when contacting support |
ErrorModel
When the API responds with 422 (Unprocessable Entity), the body is an ErrorModel, named ErrorModelV2 in the API reference,
with the following fields:
| Field | Type | Description |
|---|---|---|
code | string | The error code (see error codes). Write your error handling against this field |
message | string | Description of the error, in English. It is meant for your logs, not for your users, since it is not localized |
details | object | Additional information about the error, when there is any |
validationResults | object | When the code is ValidationError, the results of the certificate or signature validation that failed |
For instance:
{
"code": "SignatureSessionNotFound",
"message": "Signature session not found: 00000000-0000-0000-0000-000000000000"
}
Culture
The API observes the Accept-Language request header, which changes the culture of the texts the API returns. The supported cultures are:
en-US(or justen)pt-BR(or justpt)es-ES(or justes)
Error messages are not affected by this header, so they should be logged, not shown to your users. To show an error to a user, map its code
to a message of your own.
Make a first call
With your credentials and the client library in place, check that everything works.
First, check the endpoint: open the address api/system/info of the endpoint in a browser, such as
https://core.pki.rest/api/system/info. This address needs no API key and returns the version of the
instance:
{"productName":"Lacuna Rest PKI Core","productVersion":"5.0.5 RTM","spaVersion":"...","timestamp":"..."}
Then, check the API key by creating a signature session. On .NET:
using Lacuna.RestPki.Api.SignatureSessions;
var response = await restPkiService.CreateSignatureSessionAsync(new CreateSignatureSessionRequest() {
ReturnUrl = "https://localhost:5001/signature-callback",
});
// Send the user to response.RedirectUrl
Calling the API directly:
curl -X POST "https://core.pki.rest/api/signature-sessions" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "returnUrl": "https://localhost:5001/signature-callback" }'
The response brings the ID of the session and the URL of its signature page:
{
"sessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"redirectUrl": "https://core.pki.rest/..."
}
Open the redirectUrl in a browser to see the page where your users will sign. If the call fails instead:
- 401: the API key was not sent or is wrong. Check that you copied the whole key, including the application name before the
| - 403: the application doesn't have the Worker role (see Choosing roles)
- Endpoint unreachable: check the address of the endpoint and whether your server can reach it
Next steps
- Signature sessions: let your users sign documents on a page hosted by Rest PKI Core
- Two-step signatures: sign on your own page with Web PKI, or with a key held by your server
- Biometric sessions: liveness, enrollment, facial authentication and identification, and ID capture
- Webhooks: get notified when a document is signed
- Security contexts: choose which certificates are trusted
- Signature inspection: list and validate the signatures of a file
- PDF stamps: add a document timestamp to a PDF
- Referencing files: the ways to send documents to the API
- Rest PKI client tool: sign documents from the command line and from desktop applications
- Requesting timestamps: use Rest PKI Core as a timestamp provider
- Error codes: the codes the API may return