---
title: "Issue licences from MainSDK Cloud"
description: "Create a root and an issuing CA in your account's region, issue and renew a licence, revoke it with a second approver, and serve the refresh endpoint your app calls."
section: "guides"
status: "Planned for 0.6"
spec: "licence-cloud"
canonical: "https://mainsdk.dev/docs/guides/issue-licences-from-the-cloud"
updated: "2026-10-28"
---

# Issue licences from MainSDK Cloud

> Create a root and an issuing CA in your account's region, issue and renew a licence, revoke it with a second approver, and serve the refresh endpoint your app calls.

Status: Planned for 0.6 · Canonical: https://mainsdk.dev/docs/guides/issue-licences-from-the-cloud · Updated: 2026-10-28

You will create a root and an issuing CA, issue a licence for a customer, renew it, and revoke it. Private keys never leave the key service of your account's region. It takes about 15 minutes.

## You need

- A MainSDK Cloud account with the `owner` role, a passkey session from the last 5 minutes for every write, and an app that verifies licences (see [License your app](license-your-app.md)).

## 1. Create a root and pin it

`POST /v1/licence-roots` returns `{ kid, key: "ed25519:…", status }`. Put the key under `licence.roots` in `main.yaml`. An account holds at most 4 active roots.

## 2. Create an issuing CA

`POST /v1/licence-cas` with `{ root, name, products, validity }` (validity up to 5 years) returns the CA certificate envelope. Rotate it with `POST /v1/licence-cas/{kid}/rotate`: the old CA issues nothing new, but its licences stay valid.

## 3. Issue, renew and revoke

`POST /v1/licences` with an `Idempotency-Key` header and `{ sub, product, features, exp, grace, … }` returns `{ lid, token, claims }`. Renew with `POST /v1/licences/{lid}/renew` (same `lid`, higher `seq`). Suspend, resume and revoke use the matching routes and take a `reason` and a `grace`.

Revoking a CA or retiring a root needs a second person. The first call answers `MAIN-LICENCE-0024` with an `approvalId` (202). Another owner or admin repeats the same call with `approvalId` in the body to carry it out.

## 4. Point your app at the refresh endpoint

Set `licence.url` to the Cloud base URL. The app posts its tokens to `POST /v1/licences/refresh` and verifies everything in the answer on its own. Anyone may serve the same contract for their own issuer.

## Where it is stored

Every root, CA, licence, audit record and key-use record stays in the account's region (`us`, `eu` or `in`). A call to the wrong region answers 421. The Licences area of the console lists all of it and shows the audit of a licence.

The API is defined in `packages/core/contracts/cloud/licences.tsp`.
