SIGNBY KODARAPI v1

REST · JSON · eIDAS QES · EUDI-READY · POST-QUANTUM READY

API Reference

Send documents, add signers, collect qualified signatures, and download sealed ASiC-E containers — everything in the Sign by Kodar dashboard is available over HTTPS.

BASE URLhttps://api.sign.kodar.io/v1

EUDI Wallet-ready (eIDAS 2.0). Signing methods are negotiated server-side — EUDI Wallet first when available, falling back to Smart-ID and Mobile-ID automatically. Integrations built on this API today need no changes when EU Digital Identity Wallets roll out; optionally steer routing per signer with preferredMethods.

1

Authentication

Every request carries a bearer token. Keys are scoped per tenant — create and revoke them in the developer console. Keys are prefixed kdr_, shown once at creation, and stored only as a hash.

Keys grant signing authority. Never expose them client-side.

EXAMPLE REQUEST

curl https://api.sign.kodar.io/v1/documents \
  -H "Authorization: Bearer kdr_..." \
  -H "Content-Type: application/json"
2

Core endpoints

3

Signing lifecycle

draftDocument created, SHA-256 computed, signers not yet invited.
pending_signaturesInvites sent. Each signer identifies with Smart-ID / Mobile-ID and confirms the verification code.
completedAll signatures collected. ASiC-E container sealed with OCSP + qualified timestamp.
rejectedA signer declined. Terminal state.
expiredDeadline passed before completion. Re-send to start over.

Webhook payload

Set an endpoint in the console; we POST document.completed the moment the last signature lands.

{
  "event": "document.completed",
  "documentId": "7b07e940-…",
  "data": {
    "title": "Service agreement — Acme × Kodar",
    "asicePath": "documents/…/7b07e940-….asice",
    "signers": [
      { "name": "Mari Maasikas",
        "signedAt": "2026-07-04T09:20:41Z" }
    ]
  }
}

Payloads are signed — verify the X-Kodar-Signature HMAC with your signing secret.

VERIFY (NODE)

import { createHmac, timingSafeEqual } from "crypto";

const expected = "sha256=" + createHmac("sha256", secret)
  .update(rawBody).digest("hex");
const ok = timingSafeEqual(
  Buffer.from(header), Buffer.from(expected));

Errors

Consistent envelope: { error: { code, message } }

400invalid_inputMalformed body or missing field
401unauthorizedMissing or revoked API key
404not_foundNo such document in this tenant
409not_sendable / not_readyAction not allowed in the current lifecycle state
413file_too_largePDF exceeds 10 MB
415not_pdfPayload is not a PDF
429rate_limitedToo many requests — see Retry-After

Rate limits

120REQUESTS / MIN · PER KEY

When exceeded you receive 429 with a Retry-After header. Signing sessions already in progress are never interrupted.

Download OpenAPI 3.1 spec ↓

Endpoint details

POST/documents

Create a document. Pass send: true to email signing links immediately — the response then carries a signing URL per signer.

REQUEST

curl https://api.sign.kodar.io/v1/documents \
  -H "Authorization: Bearer kdr_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Service agreement — Acme × Kodar",
    "pdfBase64": "JVBERi0xLjQK...",
    "send": true,
    "signers": [
      { "firstName": "Mari", "lastName": "Maasikas",
        "idCode": "60001019906", "countryCode": "EE",
        "email": "mari@acme.ee", "phoneNumber": "+37200000766" }
    ]
  }'

RESPONSE

201 Created
{
  "id": "7b07e940-a80c-41aa-8179-eba37a59dc12",
  "status": "pending_signatures",
  "signingLinks": [
    { "signerId": "…", "email": "mari@acme.ee",
      "signingUrl": "https://sign.kodar.io/s/eyJ…" }
  ]
}
GET/documents

List your documents, newest first. Optional ?limit= (max 100).

REQUEST

curl https://api.sign.kodar.io/v1/documents?limit=10 \
  -H "Authorization: Bearer kdr_..."

RESPONSE

200 OK
{ "documents": [
  { "id": "…", "title": "…", "status": "completed",
    "sha256": "c025…f9a2", "createdAt": "2026-07-04T09:12:00Z" } ] }
GET/documents/:id

One document with per-signer status. containerReady turns true once every signer has signed.

REQUEST

curl https://api.sign.kodar.io/v1/documents/7b07e940-… \
  -H "Authorization: Bearer kdr_..."

RESPONSE

200 OK
{
  "id": "7b07e940-…", "title": "…", "status": "pending_signatures",
  "sha256": "c025…f9a2", "containerReady": false,
  "signers": [
    { "id": "…", "name": "Mari Maasikas", "email": "mari@acme.ee",
      "countryCode": "EE", "status": "signed",
      "signedAt": "2026-07-04T09:20:41Z" } ]
}
POST/documents/:id/send

Send a draft — or re-send invites. Re-sending mints fresh single-use links and invalidates previously issued ones.

REQUEST

curl -X POST https://api.sign.kodar.io/v1/documents/7b07e940-…/send \
  -H "Authorization: Bearer kdr_..."

RESPONSE

200 OK
{ "id": "7b07e940-…", "status": "pending_signatures",
  "signingLinks": [ { "signerId": "…", "email": "…", "signingUrl": "…" } ] }
GET/documents/:id/container

Download the sealed ASiC-E container. 409 not_ready until all signers have signed.

REQUEST

curl https://api.sign.kodar.io/v1/documents/7b07e940-…/container \
  -H "Authorization: Bearer kdr_..." -o agreement.asice

RESPONSE

200 OK
Content-Type: application/vnd.etsi.asic-e+zip
Content-Disposition: attachment; filename="agreement.asice"
<binary .asice bytes>
GET/algorithms

The crypto-agility switchboard: every signature algorithm the engine supports — classical (RSA, ECDSA) and post-quantum (ML-DSA, NIST FIPS 204) — and whether this deployment can sign with it right now. Algorithms are registry entries, not hardcoded: when qualified post-quantum certificates arrive, they show up here and your integration doesn't change.

REQUEST

curl https://api.sign.kodar.io/v1/algorithms \
  -H "Authorization: Bearer kdr_..."

RESPONSE

200 OK
{ "algorithms": [
  { "id": "ecdsa-sha256", "family": "EC", "displayName": "ECDSA + SHA-256",
    "digest": "SHA-256", "status": "qualified", "enabled": true },
  { "id": "ml-dsa-65", "family": "ML-DSA", "displayName": "ML-DSA-65 (FIPS 204)",
    "digest": "SHA-256", "status": "pqc-demo", "enabled": true },
  … ] }
POST/seal

Apply the organisation e-seal (Enterprise) to a PDF or an existing container. Pass algorithm: "ml-dsa-65" for the post-quantum demo seal: the content signature uses the NIST quantum-resistant standard, the qualified timestamp stays classical, and the container is a demo profile until QTSPs issue post-quantum certificates — validate it via POST /validate, which routes PQC containers to the in-house engine and reports interoperability: "pqc-demo".

REQUEST

curl https://api.sign.kodar.io/v1/seal \
  -H "Authorization: Bearer kdr_..." \
  -H "Content-Type: application/json" \
  -d '{
    "documentBase64": "JVBERi0xLjQK...",
    "filename": "agreement.pdf",
    "algorithm": "ml-dsa-65"
  }'

RESPONSE

200 OK
{ "valid": true, "errors": [],
  "signatures": [
    { "signedBy": "CN=KODAR PQC DEMO SEAL, O=Kodar OU, C=EE",
      "profile": "PQC-DEMO", "algorithm": "ML-DSA-65 (FIPS 204)",
      "trustedSigningTime": "2026-07-05T10:12:00Z" } ],
  "interoperability": "pqc-demo",
  "asiceBase64": "UEsDBBQ..." }
SIGN BY KODARAPI v1 · © 2026eIDAS QUALIFIED · EE · LV · LT