autogram-sdk

Autogram SDK - use Autogram signer from web

Autogram SDK is a TS/JS library that allows you to use the Autogram signer family (Autogram, Autogram V Mobile) from web. Not only does it provide an API to sign documents, but it also adds a UI for a consistent process of choosing the signer process (desktop/mobile).

UI is implemented using lit-element and lit-html, so it's lightweight and easy to customize and thanks to shadow DOM, it's encapsulated and it won't interfere with your styles.

npm install autogram-sdk

Some dependencies (zod, js-base64, idb-keyval, …) are declared as peer dependencies; npm 7+ installs them automatically. The self-contained builds in Distribution formats have everything inlined and need no install at all.

The package exposes four entry points. Pick the highest-level one that fits — most applications only need autogram-sdk/with-ui.

Import What it contains Where it can run
autogram-sdk/with-ui CombinedClient / createAutogramClient — the full signing flow with the built-in dialog UI for choosing between desktop and mobile signing. autogram-sdk/ui is an alias. Browser page only — importing it registers custom elements as a side effect.
autogram-sdk The headless core: DesktopClient, MobileClient, error classes (AutogramError, …), shared types, and the RPC helpers (defineRpcService, …) used to bridge contexts. Anywhere — pages, service workers, extension background scripts. No UI, no side effects.
autogram-sdk/autogram-api Low-level HTTP client (apiClient) for the Autogram desktop app's local server. Anywhere.
autogram-sdk/avm-api Low-level client for the Autogram v mobile (AVM) server API, including device pairing (AutogramVMobileIntegration) and the QR-pairing simulation helper (AutogramVMobileSimulation). Anywhere.

The layering: with-ui builds on DesktopClient/MobileClient from the core, which in turn build on autogram-api/avm-api. Drop down a level when you need your own UI (see the DesktopClient demo) or your own transport (see channels).

Every entry point is built in three flavors:

Files Format Dependencies Intended consumer
dist/*.mjs, dist/*.js + .d.ts ESM + CJS (the npm exports map) External (dependencies / peerDependencies) Projects with a bundler (Vite, webpack, …) — gives tree-shaking and dependency deduping.
dist/bundled/*.mjs ESM, self-contained Inlined <script type="module"> straight from a static server or CDN, no bundler needed.
dist/*.iife.js IIFE, self-contained (AutogramSDK global) Inlined Classic <script> tag; index-all.iife.js is the usual choice (core + UI).
import { createAutogramClient } from "autogram-sdk/with-ui";

const client = await createAutogramClient();

const { content, mimeType, signatures } = await client.sign(
{
content: "hello world",
mimeType: "text/plain",
filename: "hello.txt",
},
{
form: "XAdES",
container: "ASiC_E",
}
);
// content is Base64; signatures is [{ signedBy, issuedBy }, ...]

Pass an array to sign several documents together with a single signature ("spoločná autorizácia dokumentov"). Each document carries its own MIME type and optional XML Datacontainer parameters. Requires the Autogram desktop app 2.8.0 or newer; the method chooser is skipped (Autogram v mobile cannot do this).

const { content, mimeType } = await client.sign(
[
{
content: formXml,
mimeType: "application/xml",
filename: "form.xml",
xdcParameters: { autoLoadEform: true },
},
{
content: pdfBase64,
mimeType: "application/pdf",
encoding: "base64",
filename: "attachment.pdf",
},
],
{ form: "XAdES", container: "ASiC_E" }
);

The SDK detects the running Autogram version: 2.8.0 and newer is used through POST /api/v1/sign, older versions through the legacy POST /sign (one document only). Requests an older Autogram cannot fulfil (multiple documents, requireQualifiedCertificate, checkPDFEmbeddedAttachments) fail with an app-version-too-low error and the dialog asks the user to update Autogram.

Upgrading from 0.6.x? See docs/MIGRATION.md — legacy calls convert with fromLegacySignArgs().

Serve the file yourself or point at a CDN that mirrors npm (e.g. https://cdn.jsdelivr.net/npm/autogram-sdk/dist/…).

<script src="dist/index-all.iife.js"></script>
<script type="module">
// type="module" only for top-level await; the AutogramSDK global works
// from any script, see demos/iife-combined.html for a classic-script setup
const client = await AutogramSDK.createAutogramClient();

const { content, mimeType, signatures } = await client.sign(
{
content: "hello world",
mimeType: "text/plain",
filename: "hello.txt",
},
{
form: "XAdES",
container: "ASiC_E",
}
);
</script>

Same API as the npm build, but with dependencies inlined so the browser can load it directly:

<script type="module">
import { createAutogramClient } from "./dist/bundled/index-all.mjs";

const client = await createAutogramClient();
// …same sign() call as above
</script>

All SDK errors carry a machine-readable code. Classify them with AutogramError.is() (works even for errors that crossed a postMessage boundary, where instanceof fails):

import { AutogramError } from "autogram-sdk";

try {
await client.sign(...);
} catch (e) {
if (AutogramError.is(e, "user-cancelled")) {
// user closed the dialog — not a failure
} else if (AutogramError.is(e, "app-not-installed")) {
// point the user to autogram.slovensko.digital
} else if (AutogramError.is(e, "app-version-too-low")) {
// the dialog already asked the user to update Autogram
} else {
throw e;
}
}

See docs/API.md for the full API reference, docs/MIGRATION.md for upgrade notes, and docs/API-PROPOSAL.md for the redesign roadmap. Generated TypeDoc reference is published at https://slovensko-digital.github.io/autogram-extension/autogram-sdk/.

For most web applications the basic usage above is all you need — CombinedClient.init() called without arguments works out of the box.

Channels become relevant when the SDK runs in an environment where it cannot make direct network requests from the page. A channel is simply an object that implements the communication contract with a signing back-end (desktop app or AVM cloud service). CombinedClient delegates all actual network calls to its two channels, keeping UI and transport completely separate.

This separation makes it possible to move the network calls into a different execution context — for example a service worker or a browser-extension background script — and forward them over a message bridge instead. Autogram Extension uses this: instead of the default channels it passes its own implementations that proxy every call through the content-script ↔ injected-script message bridge.

// Simple case — use defaults, no channels needed, communicate directly
const client = await createAutogramClient();

// Advanced case — inject custom channel implementations
const client = await createAutogramClient({
mobileChannel: new MyAvmChannel(), // implements AutogramVMobileIntegrationInterfaceStateful
desktopChannel: new MyDesktopChannel(), // implements AutogramDesktopIntegrationInterface
});

A user who pairs a phone with your integration gets later signing requests as push notifications in Autogram v mobile, with no QR scan. Turn it on with pairingEnabled:

const client = await createAutogramClient({ pairingEnabled: true });

The dialog then shows a pairing link on the QR screen. Once a phone is paired there, the dialog confirms it and sends the request to the phone; the user can still go back to the signing QR. After a successful mobile signature with no paired phone, the dialog shows a success page offering pairing; sign() has already resolved by then. Users who already have a paired phone skip it.

Notifications are an optional capability of the mobile channel. The default channel supports them. A custom mobileChannel supports them only if it implements getPairingQrCodeUrl(), sendNotification() and getPairedDevices(). If it leaves them out, users sign by scanning the per-document QR code and are never asked to pair.

Pairings are bound to the integration identity (key pair + GUID). By default it is kept in the page origin's IndexedDB. Pass mobileStorage (any { get, set } store) to keep it elsewhere. See docs/API.md for details.

npm run build:release
# or
npm run build:watch

using npm run build:watch is usefult when developing using npm link

npm run generate-autogram-api-types
npm run generate-avm-api-types

Autogram Desktop types are generated from local app running on default port. AVM types are generated from server.

npm run generate-docs

The deploy-pages workflow regenerates the docs on every push to master and publishes them to https://slovensko-digital.github.io/autogram-extension/autogram-sdk/.

  1. Run npm run build:watch in the autogram-sdk directory
  2. Run npm link in the autogram-sdk directory
  3. Run npm link autogram-sdk in the project where you want to use autogram-sdk

Sometimes the link breaks and you need to do whole process again.

npm run demo

Build the lib first (npm run build), then npm run demo starts a static server on port 8080 and opens http://localhost:8080/demos/ with one demo page per build flavor:

Demo Build flavor How it loads the SDK
esm-bundled.html dist/bundled/*.mjs — ESM, dependencies inlined <script type="module">, works from any static server
esm-external.html dist/*.mjs — ESM, dependencies external (the npm package build) <script type="module"> + import map resolving bare imports to esm.sh (needs network)
iife-combined.html dist/index-all.iife.js — IIFE, dependencies inlined Classic <script> tag, AutogramSDK global; signs a PDF via CombinedClient
iife-desktop.html dist/index-all.iife.js — IIFE, dependencies inlined Classic <script> tag; headless DesktopClient with custom progress UI