---
title: "Start a headless signature"
method: POST
path: "/v1/signatures"
tags: ["Signatures"]
---

# Start a headless signature

`POST /v1/signatures`

## Request

- Base URL: `https://sign-api.tvarka.pro`
- URL: `https://sign-api.tvarka.pro/v1/signatures`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`
  - OAuth 2 (authorization code, authorization URL `https://sign-api.tvarka.pro/oauth/authorize`, token URL `https://sign-api.tvarka.pro/oauth/token`, scopes: `sign.read`, `sign.signings`)

Opens the first confirmation on the signer's phone at once and
answers `202` with its verification code. Show the code; poll
`GET /v1/signatures/{signatureId}` or wait for the webhook.

Refusals at create time are never billed: `403
headless-not-enabled` (production workspace without the
entitlement), `402 payment-required` with `recoveryUrl` when the
workspace cannot pay for one signature, `409 signer-busy` when the
signer already has an active request elsewhere (not queued; retry
once it ends), `400 validation-failed` listing every rejected
field with a JSON Pointer, `422 interaction-unavailable` when a
QR code or app link is asked for and not switched on, and `422
signer-unreachable` when the provider refused because of the person
or the request, for example when no account exists for this method.
The same request would be refused again. A `503` that
carries `Retry-After` means provably nothing started: retry with the
same Idempotency-Key. A start that may have reached the phone
answers `202` with `status: failed` and `failureReason:
initiation_unknown`, never a second start.

## Headers

- `Idempotency-Key` string

## Request body

- CreateSignatureRequest
  - `method` 'smart_id' | 'mobile_id', required
  - `interaction` object: How the signer is reached (v1.11.0). `notification` (default): a prompt on their phone and a verification code you show. `qr` and `app_link`: Smart-ID only; the signer picks the account by QR code or app link and no personal code is needed.
    - `type` 'notification' | 'qr' | 'app_link', required
  - `returnUrl` string, uri: `app_link` only, and required there: an exact HTTPS URL registered for this API client. Requires `returnState`.
  - `returnState` string: Random per-browser-session value, returned as `state`.
  - `visibleSignature` union: `pades` only (v1.13.0): the visible stamp is your choice. Omitted or `false`: no stamp. `true`: the stamp in the default corner. An object: exactly one of coordinates or an existing empty signature field, with the same checks as a hosted signer's `visibleSignature`.
    - boolean
    - union: Any workspace may place this signer's visible PDF stamp. Use either page coordinates in PDF points from the lower-left MediaBox corner, or one existing unsigned signature field. The accepted value is immutable and returned on the signer. PDF only; field binding cannot be combined with `document.flatten: true`. `page` is 1-based. Coordinates are finite PDF points (1/72 inch) in unrotated page space; x/y are offsets even when the MediaBox origin is nonzero. The whole box must fit MediaBox and CropBox. Minimum size is 148 x 52 pt; placement requires /UserUnit: 1. A field must have one usable visible widget, be unsigned and unlocked, and meet the same geometry rules. Earlier field locks, ambiguous names and fields already reserved for another signer are rejected. Explicit positions do not become cascade anchors. Do not send this property for viewers. No entitlement is needed (v1.13.1); the company logo and VIP whitelabel are separate. Omit the property to use normal corner placement; configured workspace branding still applies.
      - object
        - `page` integer, required
        - `x` number, required
        - `y` number, required
        - `width` number, required
        - `height` number, required
      - object
        - `field` string, required
  - `signer` object: Required for `notification`. Optional for `qr` and `app_link`, where `personalCode` alone accepts only that person.
    - `personalCode` string: Identity lock: only this person's signature is accepted. Never returned and never sent in webhooks. Required for `notification`.
    - `phoneNumber` string: Required for `mobile_id`, refused otherwise.
  - `document` object, required: Exactly one of `hash` or `pdf`.
    - `name` string, required
    - `profile` 'cades-detached' | 'pades', required
    - `hash` object: The digest to sign, for `cades-detached`.
      - `algorithm` 'sha256', required
      - `value` string, byte, required: Base64, exactly 32 bytes.
    - `pdf` object: The PDF to sign, for `pades`. Base64, at most 15 MiB decoded; must be an unencrypted PDF.
      - `content` string, byte, required
  - `display` object
    - `text` string: Shown in the signer's app. Smart-ID shows up to 60 characters; Mobile-ID up to 40, or 20 when the text has a Lithuanian letter with a diacritic. Printable characters only. Default: `<company name>: pasirašymas`.
  - `renderHash` object, required: Digest of what you showed the signer. Kept as evidence.
    - `algorithm` 'sha256' | 'sha384' | 'sha512', required
    - `value` string, byte, required
  - `externalId` string
  - `webhookUrl` string, uri: Public HTTPS URL.

## Response `202`

The first confirmation is on the signer's phone.

- Signature
  - `id` string, uuid, required
  - `status` 'pending' | 'signed' | 'declined' | 'expired' | 'failed' | 'cancelled', required
  - `method` 'smart_id' | 'mobile_id', required
  - `interaction` 'notification' | 'qr' | 'app_link'
  - `nextAction` NextAction: What to show the signer now (v1.11.0). `revision` grows with every step and once more at the end; ignore a webhook whose revision is older than the one you hold, and poll when unsure.
    - `type` 'compare_code' | 'confirm_certificate' | 'scan_qr' | 'open_app' | 'wait' | 'none', required
    - `revision` integer, required
    - `verificationCode` string: With `compare_code`.
    - `qrLink` string, uri: With `scan_qr`. Show as a QR code; it changes every second.
    - `refreshAfterSeconds` integer: With `scan_qr`: fetch a new link after this long.
    - `appLink` string, uri: With `open_app`: open on the signer's phone.
    - `expiresAt` string, date-time
  - `step` 'authentication' | 'signing', required: The confirmation in flight. Tvarka decides which run.
  - `verificationCode` string, nullable: Show this to the signer while `pending`.
  - `expiresAt` string, date-time
  - `externalId` string, nullable
  - `document` object
    - `name` string
    - `profile` string
    - `inputSha256` string, nullable: Hex digest the signature covers.
  - `visibleSignature` union: The stamp chosen at create (v1.13.0): `false` for none, `true` for the default corner, the accepted placement, or null for a hash.
    - boolean
    - union: Any workspace may place this signer's visible PDF stamp. Use either page coordinates in PDF points from the lower-left MediaBox corner, or one existing unsigned signature field. The accepted value is immutable and returned on the signer. PDF only; field binding cannot be combined with `document.flatten: true`. `page` is 1-based. Coordinates are finite PDF points (1/72 inch) in unrotated page space; x/y are offsets even when the MediaBox origin is nonzero. The whole box must fit MediaBox and CropBox. Minimum size is 148 x 52 pt; placement requires /UserUnit: 1. A field must have one usable visible widget, be unsigned and unlocked, and meet the same geometry rules. Earlier field locks, ambiguous names and fields already reserved for another signer are rejected. Explicit positions do not become cascade anchors. Do not send this property for viewers. No entitlement is needed (v1.13.1); the company logo and VIP whitelabel are separate. Omit the property to use normal corner placement; configured workspace branding still applies.
      - object
        - `page` integer, required
        - `x` number, required
        - `y` number, required
        - `width` number, required
        - `height` number, required
      - object
        - `field` string, required
  - `failureReason` 'identity_mismatch' | 'certificate_not_qualified' | 'certificate_rotated' | 'provider_error' | 'timestamp_unavailable' | 'initiation_unknown': `identity_mismatch` - the certificate belongs to another person. `certificate_not_qualified` - the certificate cannot sign documents. `certificate_rotated` - the signer's certificate changed since Tvarka last saw it; the new one is kept, so a retry needs one confirmation. `provider_error` - the signing service failed. `timestamp_unavailable` - no qualified timestamp could be obtained. `initiation_unknown` - the start may have reached the signer's phone but no answer came back; it is never repeated. Ask the signer to dismiss any prompt and retry after two minutes. None of these is billed.
  - `sandbox` boolean
  - `completionMode` 'signed' | 'sandbox_simulation'
  - `createdAt` string, date-time, required
  - `completedAt` string, date-time, nullable
  - `result` object: Present once `signed`.
    - `profile` string
    - `level` string, nullable: For example CAdES-BASELINE-LT.
    - `sha256` string
    - `bytes` integer
    - `signingTime` string, date-time, nullable
    - `timestampTime` string, date-time, nullable
    - `certificate` object, nullable
      - `subjectCommonName` string
      - `issuer` string
      - `serialNumber` string: Certificate serial, hex.
      - `notAfter` string, date-time
      - `qualified` boolean: The certificate states it is qualified and on a qualified signature creation device. A statement in the certificate, not a trusted-list verdict.
    - `validation` object, nullable: Advisory. `notApplicable` for `cades-detached`: a detached signature over a hash is validated beside the document, which Tvarka never receives.
    - `available` boolean: False once the artifact was erased.

## Other responses

- `400`: An RFC 9457 problem document.
- `401`: An RFC 9457 problem document.
- `402`: An RFC 9457 problem document.
- `403`: An RFC 9457 problem document.
- `409`: The signer already has an active request, or the Idempotency-Key was reused with other input.
- `413`: An RFC 9457 problem document.
- `429`: An RFC 9457 problem document.
- `503`: An RFC 9457 problem document.

---

[API](https://skmtc.dev/tvarka/apis/tvarka-sign-api.md) · [All operations](https://skmtc.dev/tvarka/apis/tvarka-sign-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tvarka/apis/tvarka-sign-api/revisions/e3fdd995c013?raw)
