Tidvis
Developers · Enterprise

Tidvis Sign Public API

REST API v1 and webhooks for building your own integrations with Tidvis Sign. OAuth2 client credentials, signed webhooks and the full agreement lifecycle.

Quick start

Base URL: https://tidvis.se/api/public/v1. All calls use JSON. The Public API is part of the Enterprise plan.

  1. 1. Create an API client under Sign → Settings → API and save your client_id and client_secret.
  2. 2. Exchange them for an access_token via OAuth2 client credentials.
  3. 3. Create an agreement, upload a PDF, add participants and send.
curl -X POST https://tidvis.se/api/public/v1/oauth/access-token \
  -H "Content-Type: application/json" \
  -d '{"client_id":"tvc_...","client_secret":"tvs_..."}'

Authentication

OAuth2 client credentials. Exchange client_id+client_secret for a JWT valid for 1 hour. Send Authorization: Bearer <access_token> on every subsequent call.

POST/oauth/access-token

Issue an access token (1h TTL).

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": "2026-06-07T13:00:00.000Z"
}
DELETE/oauth/access-token

Revoke the current token (requires Authorization header).

Agreements

POST/agreements

Create a draft agreement (status: draft).

curl -X POST https://tidvis.se/api/public/v1/agreements \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Employment contract Anna","expires_in_days":14,"bankid_required":true}'
GET/agreements

List agreements. Supports ?status, ?limit, ?cursor.

GET/agreements/:id

Fetch an agreement with participants and status.

GET/agreements/:id/events

Audit trail (sent, viewed, signed, completed...).

GET/agreements/:id/download

Fetch the signed PDF (returns a signed URL or binary content).

Participants

POST/agreements/:id/participants

Add a signer (only in draft state).

{
  "name": "Anna Andersson",
  "email": "anna@example.com",
  "role": "signer"
}

PDF documents

PUT/agreements/:id/documents/main

Upload the main document. Accepts application/pdf (binary) or JSON with base64.

# JSON / base64
curl -X PUT https://tidvis.se/api/public/v1/agreements/$ID/documents/main \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"filename":"agreement.pdf","content_base64":"JVBERi0..."}'

# Or binary
curl -X PUT https://tidvis.se/api/public/v1/agreements/$ID/documents/main \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @agreement.pdf

Lifecycle

POST/agreements/:id/lifecycle

Send or cancel an agreement.

{"action": "send"}   // or "cancel"

BankID

You can require Swedish BankID signing per agreement. Set bankid_required: true on creation (or via PATCH before sending). When the agreement is sent each participant signs with BankID on mobile or desktop instead of drawing a signature.

Requirements

  • The account must have the Sign Pro plan and the BankID add-on enabled.
  • Pricing: 100 BankID signatures included per month, then 5 SEK/signature.
  • Without the add-on, POST /agreements/:id/lifecycle with action: "send" returns 402 bankid_disabled.

Create a BankID agreement

curl -X POST https://tidvis.se/api/public/v1/agreements \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Employment contract Anna",
    "bankid_required": true
  }'

Response (abbreviated):

{
  "id": "agr_...",
  "status": "draft",
  "bankid_required": true,
  "document": { "uploaded": false, "sha256": null },
  "participants": []
}

Webhook payload when BankID is used

For agreements with bankid_required: true, the agreement.signed event is enriched with a signature block. For privacy reasons, neither personal identity numbers, certificates nor OCSP responses are exposed via the API or webhooks.

{
  "event": "agreement.signed",
  "agreement_id": "agr_...",
  "participant": { "id": "p_...", "email": "anna@example.com" },
  "signature": {
    "method": "bankid",
    "signer_name": "Anna Andersson",
    "signed_at": "2026-06-11T08:42:11.000Z"
  }
}

Webhooks

Tidvis delivers events to your URL via POST JSON. Every request is HMAC-SHA256 signed in the header X-Tidvis-Signature: sha256=<hex> based on your signing_secret and the raw body. Failed deliveries are retried with exponential backoff for up to 24h.

POST/webhooks

Register a webhook.

{
  "client_id": "<api_client uuid>",
  "url": "https://your-app.com/webhooks/tidvis",
  "events": ["agreement.sent","agreement.signed","agreement.completed"]
}
GET/webhooks

List registered webhooks.

DELETE/webhooks/:id

Remove a webhook.

Events

  • agreement.sent
  • agreement.viewed
  • agreement.signed
  • agreement.completed
  • agreement.cancelled
  • agreement.expired

For agreements with bankid_required: true, the agreement.signed/agreement.completed events include a signature block. See BankID.

Verify signature (Node.js)

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const given = (header || "").replace(/^sha256=/, "");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}

Error codes

HTTPCodeMeaning
400invalid_requestMalformed input.
401unauthorizedMissing or invalid token.
402plan_requiredAccount lacks the Enterprise plan. Includes upgrade_url.
402bankid_disabledAgreement has bankid_required: true but the account lacks the BankID add-on.
403forbiddenNo permission for the resource.
404not_foundResource not found.
409conflictInvalid state transition (e.g. sending an already sent agreement).
429rate_limitedToo many requests.
500server_errorServer error – retry.

Rate limits

Default: 60 requests/minute per client and 600/hour for uploads. When exceeded you'll get 429 rate_limited with a Retry-After header. Need more? Contact us.

MCP & AI agents

Tidvis Sign exposes a Model Context Protocol server so AI agents (ChatGPT, Claude Desktop, custom agents) can create, send and track agreements with a single tool call. Discovery manifest at /.well-known/mcp.json. A dedicated landing page lives at /en/developers/mcp.

Endpoint

POST https://tidvis.se/api/mcp
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json, text/event-stream

Scopes

API tokens can be restricted to specific scopes. MCP access requires mcp:connect plus any combination of:

  • agreements:read – fetch agreements & events
  • agreements:create – create drafts & participants
  • agreements:send – send agreements for signing
  • agreements:cancel – cancel agreements
  • billing:checkout – generate checkout link
  • mcp:connect – required for MCP access

Available tools

  • tidvis_sign_create_agreement
  • tidvis_sign_add_participant
  • tidvis_sign_upload_pdf
  • tidvis_sign_send_agreement
  • tidvis_sign_cancel_agreement
  • tidvis_sign_get_agreement
  • tidvis_sign_list_events
  • tidvis_sign_create_checkout

Claude Desktop configuration

{
  "mcpServers": {
    "tidvis-sign": {
      "url": "https://tidvis.se/api/mcp",
      "headers": { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
    }
  }
}

Agent checkout & pay-per-agreement

Two ways for an agent to let the end customer pay:

  • Sign Pro (subscription) – monthly fee per seat, unlimited agreements. Use tidvis_sign_create_checkout with product: "sign_pro_monthly" and the desired number of seats.
  • Pay-per-agreement – 19 SEK/agreement as prepaid credits, ideal for low-volume agents. Use product: "sign_per_agreement" and a credit count (1–500). Credits are consumed automatically when send_agreement runs on free-plan accounts.

The checkout tool returns a Stripe-hosted URL the agent shows to the end customer. A 402 plan_required on send_agreement means the account has neither credits nor Sign Pro – the response includes an upgrade_url the agent can link to.

Ready to see Tidvis?

Book a no-obligation demo. We'll show you the system tailored to your operation, with no sales pressure.