---
title: "REST API"
description: "CloudHub REST API reference: the eight operations, the X-Api-Key header, request and response models, and every error code with what to do about it."
canonical: "https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api"
locale: "en"
product: "CloudHub"
last_updated: "2026-10-12"
---

# REST API

CloudHub's API has eight operations. The client libraries wrap them, but any HTTP client can call
them directly; this page documents the wire format. The same API is described interactively, as
OpenAPI, at [cloudhub.lacunasoftware.com/swagger](https://cloudhub.lacunasoftware.com/swagger).

## Conventions

- **Base URL**: `https://cloudhub.lacunasoftware.com`.
- **Authentication**: every operation requires your API key in the `X-Api-Key` header. A request
  without it, or with an unknown key, gets HTTP 401 with an empty body.
- **JSON**: request and response bodies are JSON, with camelCase property names.
- **Binary values** (hashes, certificates, signatures) travel as base64 strings. The certificate and
  sign-hash operations return a bare JSON string, such as `"MIIH…"`.
- **Enumerations** travel as strings, such as `"SingleSignature"` or `"CPF"`. The numeric values the
  1.x clients send (`1` for `SingleSignature`) are still accepted.
- **Timeouts**: signing waits on the provider. Allow up to two minutes for `sign-hash`.

| Operation | Purpose |
|---|---|
| [`POST /api/sessions`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#post-apisessions) | Create a session at every provider that holds a certificate for the signer |
| [`POST /api/sessions/services/{name}`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#post-apisessionsservicesname) | Create a session at one provider |
| [`GET /api/sessions/services`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionsservices) | Discover providers without creating a session |
| [`GET /api/sessions/services/{name}/availability`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionsservicesnameavailability) | Ask one provider whether it holds a certificate |
| [`GET /api/sessions/certificate`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionscertificate) | Read the session's certificate |
| [`GET /api/v2/sessions/certificate`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apiv2sessionscertificate) | Read the session's certificate, with its alias and provider |
| [`POST /api/sessions/sign-hash`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#post-apisessionssign-hash) | Sign a hash with the session's certificate |
| [`GET /api/sessions/custom-state`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionscustom-state) | Read back the `customState` given when the session was created |

## Sessions

### POST /api/sessions

Creates a session. With an identifier, CloudHub runs [discovery](https://docs.lacunasoftware.com/en-us/articles/cloudhub/how-it-works#discovery) and
returns only the providers that hold a certificate for it; without one, it returns every provider.

| Body field | Type | Required | Description |
|---|---|---|---|
| `redirectUri` | string | Yes | Absolute URI CloudHub sends the user back to, with `session` appended. Must be [registered for your key](https://docs.lacunasoftware.com/en-us/articles/cloudhub/how-it-works#redirect-uris). |
| `identifier` | string | No | The signer's CPF or CNPJ, digits only. |
| `identifierType` | `CPF` or `CNPJ` | No | How to read `identifier`. When omitted, more than 11 digits means a CNPJ. |
| `type` | [session type](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#trustservicesessiontypes) | No | What the user authorizes. Defaults to `SingleSignature`. |
| `lifetimeInSeconds` | integer | No | The session lifetime to ask the provider for. The provider may grant less. |
| `customState` | string | No | Your own data, kept with the session and returned by [`GET /api/sessions/custom-state`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionscustom-state). |
| `discover` | boolean | No | Whether to run discovery. Defaults to `true` when `identifier` is given. `false` returns every provider and passes `identifier` to each as a login hint. `true` requires `identifier`. |

```bash
curl https://cloudhub.lacunasoftware.com/api/sessions \
  -H "X-Api-Key: $CLOUDHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "12345678909", "redirectUri": "https://app.example.com/sign/complete", "type": "SingleSignature"}'
```

The response is a [`SessionModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#sessionmodel):

```json
{
  "services": [
    {
      "serviceInfo": {
        "serviceName": "BirdID",
        "provider": "SOLUTI",
        "endpoint": "https://api.birdid.com.br/",
        "badgeUrl": "https://cdn.lacunasoftware.com/img/psc/birdid.png"
      },
      "authUrl": "https://api.birdid.com.br/oauth/authorize?client_id=…"
    }
  ]
}
```

Errors: `InvalidRedirectUri`, `UnauthorizedRedirectUri`, `IdentifierRequiredToDiscover`; HTTP 400
when `redirectUri` is missing.

### POST /api/sessions/services/\{name\}

Creates a session at one provider, without discovery. Use it when the user has already chosen the
provider. `name` is a `serviceName` as CloudHub returns it, such as `BirdID`.

The body takes the same fields as [`POST /api/sessions`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#post-apisessions) except `identifierType`.
`identifier`, when given, is passed to the provider as a login hint; `discover` is ignored.

The response is a single [`TrustServiceAuthParametersModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#trustserviceauthparametersmodel):
`serviceInfo` and `authUrl`.

Errors: `ServiceNotFound` (with `details.name`), `InvalidRedirectUri`, `UnauthorizedRedirectUri`.

## Discovery

### GET /api/sessions/services

Runs discovery without creating a session, and returns the providers that hold a certificate for
the identifier as a list of [`TrustServiceInfoModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#trustserviceinfomodel). There is no `authUrl`
in this response.

| Query parameter | Required | Description |
|---|---|---|
| `identifier` | Yes | The CPF or CNPJ, digits only. |
| `identifierType` | No | `CPF` (default) or `CNPJ`. |

```bash
curl "https://cloudhub.lacunasoftware.com/api/sessions/services?identifier=12345678909" \
  -H "X-Api-Key: $CLOUDHUB_API_KEY"
```

A provider that fails to answer is left out of the list.

### GET /api/sessions/services/\{name\}/availability

Asks one provider whether it holds a certificate for the identifier. Takes the same query
parameters as [`GET /api/sessions/services`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apisessionsservices).

```json
{
  "discoveryAvailable": true,
  "certificateFound": true
}
```

`discoveryAvailable` is `false` when the provider could not answer; `certificateFound` is then
`null`.

Errors: `ServiceNotFound` (with `details.name`).

## Using a session

These operations take the `session` value your redirect URI received. They fail with
`SessionInvalidOrAlreadyUsed` when CloudHub doesn't know the session or the provider no longer
accepts it. The certificate and sign-hash operations also fail with `SessionExpired` once the
session's lifetime is over.

### GET /api/sessions/certificate

Returns the session's certificate, DER-encoded and then base64-encoded, as a JSON string. When the
provider holds several certificates for the user, CloudHub picks the one that is currently valid
and most recently issued.

```bash
curl "https://cloudhub.lacunasoftware.com/api/sessions/certificate?session=9f2c…e81a" \
  -H "X-Api-Key: $CLOUDHUB_API_KEY"
```

```json
"MIIHGjCCBQKgAwIBAgI…"
```

### GET /api/v2/sessions/certificate

Returns the same certificate as a [`CertificateModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#certificatemodel), with its alias and the
provider's service name:

```json
{
  "content": "MIIHGjCCBQKgAwIBAgI…",
  "alias": "a5f1…",
  "serviceName": "BirdID"
}
```

Pass `alias` to `sign-hash` as `certificateAlias` to sign with exactly this certificate.

### POST /api/sessions/sign-hash

Signs a hash with the user's key and returns the signature value, base64-encoded, as a JSON string.

| Body field | Type | Required | Description |
|---|---|---|---|
| `session` | string | Yes | The session value. |
| `hash` | string | Yes | The hash to sign, base64-encoded. |
| `digestAlgorithmOid` | string | One of these two | The OID of the hash's digest algorithm, such as `2.16.840.1.101.3.4.2.1` for SHA-256. Takes precedence over `digestAlgorithm`. |
| `digestAlgorithm` | string | One of these two | The algorithm's name, such as `SHA-256`. |
| `certificateAlias` | string | No | The certificate to sign with, from [`GET /api/v2/sessions/certificate`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#get-apiv2sessionscertificate). Defaults to the certificate `GET /api/sessions/certificate` returns. |

```bash
curl https://cloudhub.lacunasoftware.com/api/sessions/sign-hash \
  -H "X-Api-Key: $CLOUDHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"session": "9f2c…e81a", "hash": "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=", "digestAlgorithmOid": "2.16.840.1.101.3.4.2.1"}'
```

```json
"Qy1kZ3N0b3JlIHNpZ25hdHVyZSB2YWx1ZS4uLg…"
```

Errors: `DigestAlgorithmNameOrOidIsRequired`, `InvalidDigestAlgorithm`, `SessionExpired`,
`SessionInvalidOrAlreadyUsed`.

### GET /api/sessions/custom-state

Returns the `customState` given when the session was created, as a JSON string, or `null` when
there was none. The `session` query parameter is required.

Errors: `SessionInvalidOrAlreadyUsed`.

## Models

### SessionModel

| Field | Type | Description |
|---|---|---|
| `services` | [`TrustServiceAuthParametersModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#trustserviceauthparametersmodel)[] | One entry per provider. Empty when none holds a certificate for the identifier. |

### TrustServiceAuthParametersModel

| Field | Type | Description |
|---|---|---|
| `serviceInfo` | [`TrustServiceInfoModel`](https://docs.lacunasoftware.com/en-us/articles/cloudhub/rest-api#trustserviceinfomodel) | The provider. |
| `authUrl` | string | Where to send the user to authorize at this provider. |

### TrustServiceInfoModel

| Field | Type | Description |
|---|---|---|
| `serviceName` | string | The provider's name in CloudHub, such as `BirdID`. It goes in the path of the single-provider operations. |
| `provider` | string | The company that operates the service, such as `SOLUTI`. |
| `endpoint` | string | The provider's API address. |
| `badgeUrl` | string | The provider's logo. May be null. |

### CertificateModel

| Field | Type | Description |
|---|---|---|
| `content` | string | The certificate, DER-encoded, then base64-encoded. |
| `alias` | string | The certificate's identifier at the provider. |
| `serviceName` | string | The provider the certificate came from. |

### GetServiceAvailabilityResponse

| Field | Type | Description |
|---|---|---|
| `discoveryAvailable` | boolean | Whether the provider answered. |
| `certificateFound` | boolean or null | Whether it holds a certificate for the identifier. Null when it did not answer. |

### TrustServiceSessionTypes

`SingleSignature`, `MultiSignature`, `SignatureSession`, `AuthenticationSession`. See
[Session types](https://docs.lacunasoftware.com/en-us/articles/cloudhub/how-it-works#session-types).

### IdentifierTypes

`CPF`, `CNPJ`.

## Errors

| HTTP status | Body | Meaning |
|---|---|---|
| 400 | A validation problem, listing the fields | A required field is missing or malformed, such as `redirectUri`. |
| 401 | Empty | The `X-Api-Key` header is missing or the key is unknown. |
| 422 | `{ "code", "message", "details" }` | CloudHub refused the request. `code` is one of the codes below. |
| 500 | A JSON string with a short code, such as `"4F1A2B"` | An unexpected failure, often at the provider. Quote the code to Lacuna support. |

```json
{
  "code": "UnauthorizedRedirectUri",
  "message": "Unauthorized redirect URI",
  "details": {
    "redirectUri": "https://app.example.com/sign/complete"
  }
}
```

| Code | Meaning | What to do |
|---|---|---|
| `InvalidRedirectUri` | `redirectUri` is not an absolute URI. | Send a full URI, with scheme and host. |
| `UnauthorizedRedirectUri` | `redirectUri` is not registered for your key. `details.redirectUri` shows it. | Ask Lacuna support to register it. See [Redirect URIs](https://docs.lacunasoftware.com/en-us/articles/cloudhub/how-it-works#redirect-uris). |
| `IdentifierRequiredToDiscover` | `discover` is `true` but there is no `identifier`. | Send the identifier, or drop `discover`. |
| `ServiceNotFound` | No provider has that name. `details.name` shows it. | Use a `serviceName` CloudHub returned. |
| `DigestAlgorithmNameOrOidIsRequired` | `sign-hash` has neither `digestAlgorithm` nor `digestAlgorithmOid`. | Send one of them. |
| `InvalidDigestAlgorithm` | The digest algorithm name or OID is not recognized. | Send the OID your signature library reports. |
| `SessionInvalidOrAlreadyUsed` | CloudHub doesn't know the session, or the provider no longer accepts it, for example because it was already used. | Create a new session. |
| `SessionExpired` | The session's lifetime is over. It can happen on the first use, when the user took long to authorize. | Create a new session and send the user to the provider again. |
