Tidvis
Utviklere · Enterprise

Tidvis Sign Public API

REST API v1 og webhooks for å bygge egne integrationer mot Tidvis Sign. OAuth2 client credentials, signerte webhooks og fullt avtaleløp.

Hurtigstart

Base URL: https://tidvis.se/api/public/v1. Alle kall bruger JSON. Public API er del av Enterprise-planen.

  1. 1. Opprett en API-klient under Sign → Innstillinger → API og lagre client_id og client_secret.
  2. 2. Bytt dem mot et access_token via OAuth2 client credentials.
  3. 3. Opprett en aftale, upload en PDF, legg til deltakere og 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_..."}'

Autentisering

OAuth2 client credentials. Bytt client_id+client_secret mot en JWT som er gyldig i 1 time. Send Authorization: Bearer <access_token> på alle påfølgende kall.

POST/oauth/access-token

Hent et access token (1t TTL).

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

Tilbakekall gjeldende token (krever Authorization-header).

Avtaler

POST/agreements

Opprett et avtaleutkast (status: draft).

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

List aftaler. Støtter ?status, ?limit, ?cursor.

GET/agreements/:id

Hent en aftale med deltakere og status. Også status-pollingendepunktet — se under.

GET/agreements/:id/events

Audit-spor (sent, viewed, signed, completed...).

GET/agreements/:id/download

Hent signert PDF (returnerer signed URL eller binært innhold).

Poll signeringsstatus

Tidvis Sign har ingen egen /status-ressurs — GET /agreements/:id er pollingendepunktet. Responsen inneholder avtalens status samt participants[].status og signed_at per part, så du kan vise f.eks. "1 av 2 har signert" i dit eget UI uden å vente på webhook.

Anbefaling: bruk webhooks (agreement.viewed, agreement.signed, agreement.completed) som primær kanal og fall tilbage på polling hvert 30. sekund når webhook ikke er et alternativ. Avtalestatus kan være draft, sent, partially_signed, completed, declined eller cancelled.

# Poll status og tell signerte
curl -s https://tidvis.se/api/public/v1/agreements/$ID \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{
      status,
      signed: ([.participants[] | select(.status == "signed")] | length),
      total: (.participants | length),
      participants: [.participants[] | {name, email, status, signed_at}]
    }'

Eksempel-svar (1 av 2 signert):

{
  "status": "partially_signed",
  "signed": 1,
  "total": 2,
  "participants": [
    { "name": "Anna Andersson", "email": "anna@example.com", "status": "signed",  "signed_at": "2026-06-17T09:14:22Z" },
    { "name": "Erik Eriksson",  "email": "erik@example.com",  "status": "viewed",  "signed_at": null }
  ]
}

Deltakere

POST/agreements/:id/participants

Legg til en signatar (kun i draft-tilstand).

{
  "name": "Anna Andersson",
  "email": "anna@example.com",
  "role": "signer",
  "job_title": "Daglig leder",
  "phone": "+4791234567",
  "personal_id_masked": "19800101-XXXX",
  "notifications_enabled": true
}
POST/agreements/:id/participants/:pid/decline

Avvis avtalet for en bestemt deltaker. Setter avtalets status til 'declined'.

{ "reason": "Vilkårene er ikke akseptable" }
POST/agreements/:id/participants/:pid/delegate

Delegér signering til en ny person. Den opprinnelige deltakeren merkes 'delegated'.

{
  "name": "Erik Eriksson",
  "email": "erik@example.com",
  "job_title": "Finansdirektør",
  "phone": "+4790123456",
  "message": "Henviser til Erik som håndterer signering."
}
PATCH/agreements/:id/participants/:pid/notifications

Slå av/på påminnelses-e-poster for en enkelt deltaker.

{ "enabled": false }
GET/agreements/:id/chat

List chat-meldinger mellem agenten og deltakerne på en aftale.

POST/agreements/:id/chat

Send en chat-melding. Angi participant_id for å videreformidle en melding fra en deltaker. Utløser webhooken agreement.chat_message.

{
  "body": "Hei, kan jer se gennem vedlegg 2?",
  "sender_label": "Tidvis Sign Agent",
  "participant_id": "8a3..."
}

PDF-dokumenter

PUT/agreements/:id/documents/main

Upload hoveddokumentet. Støtter application/pdf (binært) eller JSON med 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":"aftale.pdf","content_base64":"JVBERi0..."}'

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

Livssyklus

POST/agreements/:id/lifecycle

Send eller avbryt en aftale.

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

MitID

Du kan kreve svensk MitID-signering per aftale. Sett bankid_required: true ved opprettelse (eller via PATCH før sending). Når aftalen sendes signerer hver deltaker med MitID på mobil eller desktop i stedet for å tegne sin signatur.

Krav

  • Kontoen skal ha planen Sign Pro og tillegget MitID aktivert.
  • Pris: 100 MitID-signaturer inkludert per måned, deretter 5 SEK/signatur.
  • Uten tillegget returnerer POST /agreements/:id/lifecycle med action: "send" feilen 402 bankid_disabled.

Opprett MitID-aftale

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

Svar (forkortet):

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

Webhook-payload når MitID bruges

For aftaler med bankid_required: true berikes agreement.signed-hendelsen med en signature-blokk. Av personvernhensyn eksponeres verken personnummer, sertifikater eller OCSP-svar via API-et eller 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"
  }
}

Feltet signature.method er alltid en av "otp_email" eller "bankid". Avtaler med blandede deltakere logger metoden per signatar.

MitID-identifisering før åpning

Eget tillæg som tvinger mottakeren til å legitimere seg med MitID før dokumentet vises. Det er en gate foran selve PDF-en og er uavhengig av valgt signaturmetode — du kan altså kreve MitID-legitimering og fortsatt la signeringen skje med engangskode på e-post, klik-signatur eller tegnet signatur. Kombineres gjerne med bankid_required: true når du vil ha både identifisering før åpning og MitID-signering ved undertegning.

Slå på ved opprettelse

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

Svar (forkortet):

{
  "id": "agr_...",
  "status": "draft",
  "bankid_required": false,
  "bankid_identify_required": true,
  "participants": []
}

Atferd for mottakeren

  • Når mottakeren åpner lenken vises en MitID-gate i stedet for PDF-en.
  • Mottakeren skal starte MitID på mobil eller via QR-kode og bekrefte legitimeringen.
  • Først deretter åpnes PDF-en og valgt signaturmetode bliver aktiv.
  • "viewed"-hendelsen logges etter legitimeringen, ikke ved første klik på lenken.

Krav og pris

  • Kontoen skal ha Sign Pro og tillegget MitID aktivert — samme krav som bankid_required.
  • Identifiseringer teller ikke mot MitID-kvoten på 100 signeringer/mnd. Kun faktiske MitID-signeringer (bankid_required: true) debiteres 5 SEK/stk ut over inkluderte.
  • Uten tillegget returnerer POST /agreements/:id/lifecycle med action: "send" feilen 402 bankid_disabled.

Webhook-payload

En egen hendelse agreement.identified sendes når en mottaker har legitimert seg. Personnummer, sertifikater og OCSP-svar eksponeres aldri via API-et.

{
  "event": "agreement.identified",
  "agreement_id": "agr_...",
  "participant": { "id": "p_...", "email": "anna@example.com" },
  "identification": {
    "method": "bankid",
    "signer_name": "Anna Andersson",
    "identified_at": "2026-06-12T10:21:04.000Z"
  }
}

Webhooks

Tidvis leverer hendelser til din URL via POST JSON. Hvert kall er signert med HMAC-SHA256 i headeren X-Tidvis-Signature: sha256=<hex> basert på din signing_secret og raw body. Mislykkede leveranser forsøkes på nytt med eksponentiell backoff i opptil 24t.

POST/webhooks

Registrer en webhook.

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

List registrerte webhooks.

DELETE/webhooks/:id

Slett en webhook.

Hendelser

  • agreement.sent
  • agreement.viewed
  • agreement.signed
  • agreement.completed
  • agreement.cancelled
  • agreement.declined
  • agreement.delegated
  • participant.notifications_changed
  • agreement.chat_message
  • agreement.expired
  • agreement.identified

For aftaler med bankid_required: true inkluderer agreement.signed/agreement.completed også en signature-blokk. Se MitID.

Verifiser signatur (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));
}

Feilkoder

HTTPCodeBetydning
400invalid_requestFeil input.
401unauthorizedMangler/ugyldig token.
402plan_requiredKontoen mangler Enterprise-plan. Inkluderer upgrade_url.
402bankid_disabledAvtalen har bankid_required: true men kontoen mangler MitID-tillegget.
403forbiddenMangler rettigheter til ressursen.
404not_foundRessursen blev ikke fundet.
409conflictUgyldig tilstandsovergang (f.eks. sende allerede sendt aftale).
429rate_limitedFor mange kall.
500server_errorServerfeil – prøv igjen.

Rate-grenser

Standardgrense: 60 kall/minutt per klient og 600/time for opplastinger. Ved overskridelse får du 429 rate_limited med Retry-After-header. Trenger du mer? Kontakt oss.

MCP & AI-agenter

Tidvis Sign eksponerer en Model Context Protocol-server slik at AI-agenter (ChatGPT, Claude Desktop, egne agenter) kan opprette, sende og spore aftaler med ét enkelt verktøykall. Discovery-manifest findes på /.well-known/mcp.json. En dedikert landingsside ligger på /da/udviklere/mcp.

Endepunkt

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

Scopes

API-tokens kan begrenses til spesifikke scopes. For MCP kreves mcp:connect + valgfri kombinasjon av:

  • agreements:read – hent aftaler & events
  • agreements:create – opprett utkast & deltakere
  • agreements:send – send aftaler til signering
  • agreements:cancel – avbryt aftaler
  • billing:checkout – generer checkout-lenke
  • mcp:connect – kreves for MCP-adgang

Tilgjengelige værktøjer

  • 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
  • tidvis_sign_decline_agreement
  • tidvis_sign_delegate_signing
  • tidvis_sign_set_participant_notifications
  • tidvis_sign_list_chat_messages
  • tidvis_sign_post_chat_message

Claude Desktop-konfigurasjon

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

Agent-checkout & betal-per-aftale

To måter en agent kan la sluttkunden betale:

  • Sign Pro (abonnement) – månedsavgift per sete, ubegrenset antal aftaler. Bruk tidvis_sign_create_checkout med product: "sign_pro_monthly" og ønsket antal seter.
  • Betal per aftale – 19 SEK/aftale som forhåndsbetalte kreditter, perfekt for lavvolums-agenter. Bruk product: "sign_per_agreement" og antal kreditter (1–500). Kreditter trekkes automatisk når send_agreement kjøres på free-plan-kontoer.

Checkout-verktøyet returnerer en Stripe-hostet URL som agenten viser til sluttkunden. Ved 402 plan_requiredsend_agreement mangler kontoen både kreditter og Sign Pro – svaret inneholder en upgrade_url agenten kan lenke til.

Klar til at se Tidvis?

Book en uforpligtende demo. Vi viser systemet tilpasset jeres virksomhed — uden salgspres.