Relation Sign API

Send PDF-er til signering fra et annet system, følg statusen, og hent dem forseglet. Alle svar er JSON, og feil har formen { "error": "melding" } med en norsk melding som kan vises brukeren.

Produksjon
https://sign.relationlabs.no/api/v1
Lokal utvikling
http://localhost:8090/api/v1

OpenAPI 3.1 (openapi.yaml)Last den inn i Postman, Insomnia eller en kodegenerator.

Kom i gang

  1. 1En administrator lager en API-nøkkel under Integrasjoner. Velg «Bare lese» for systemer som bare skal hente status og dokumenter.
  2. 2Send nøkkelen som Authorization: Bearer på hvert kall. Manglende, utløpt eller tilbakekalt nøkkel gir 401.
  3. 3Legg til en webhook, så får systemet beskjed når noen signerer i stedet for å spørre.
Shell
export RS=https://sign.relationlabs.no/api/v1
export RS_KEY=rs_live_...
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes"

Signering i deres egen flyt

For hvilket som helst system, for eksempel regnskap, kontrakter, eiendomsmegling eller CRM: brukeren trykker «Signer» i systemet deres, signerer med BankID, MitID eller finsk eID hos oss og kommer rett tilbake. Vi sender ingen e-post til den som signerer slik.

  1. 1En administrator legger inn adressen til systemet deres under Integrasjoner → API-nøkkelen → Signering i eget system, sammen med navnet brukeren skal se på knappen «Fortsett i …».
  2. 2Opprett og send signeringen i ett kall, med delivery: "none" og returnUrl på signataren. Svaret har signingUrl: send brukeren dit.
  3. 3Etter signeringen kommer brukeren tilbake til returnUrl med rs_status (signed, declined eller aborted). Stol på webhooken eller GET /envelopes/{id}, ikke på adressen.
Shell
curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" -d '{
  "title": "Årsregnskap 2026", "send": true, "fileBase64": "…",
  "signers": [{
    "name": "Kari Regnskap", "email": "kari@byra.no", "method": "bankid",
    "delivery": "none",
    "returnUrl": "https://app.eksempel.no/dokumenter/123"
  }]
}'
# Svaret: signers[0].signingUrl → send brukeren dit.
# Tilbake: https://app.eksempel.no/dokumenter/123?rs_envelope=…&rs_signer=…&rs_status=signed

Hele beskrivelsen: feltene, fast rekkefølge med signer.ready, tillatte adresser og reserveløsningen

Relation Sign i AI-agenten din (MCP)

relation-sign-mcp er en MCP-server som lar din egen AI-agent bruke Relation Sign. Du skriver det du vil ha gjort, for eksempel:

  • «Send kontrakten til Daniel for signering»
  • «Har Daniel signert?»
  • «Purr på Gressvik-kontrakten»
  • «Lag et utkast»
  • «Send den til meg, jeg signerer selv»
  • «Svar på kommentaren»
  • «Last ned den signerte»

Agenten spør om det som mangler. Hvem Daniel er, slås opp i Kontakter og blant kollegene, og finnes det flere, spør den hvilken. Den spør hvordan de skal signere og om mobilnummer for SMS. Så viser den en oppsummering og sender først når du har sagt ja.

Slik kobler du til

  1. 1Lag en personlig nøkkel: menyen øverst til høyre → Min profil → Personlige nøkler → Ny nøkkel. Kopier nøkkelen, den vises bare én gang.
  2. 2Installer relation-sign-mcp på maskinen der agenten kjører:
Shell
curl -fsSL https://sign.relationlabs.no/mcp/install.sh | sh
  1. 3Koble den til agenten med nøkkelen i RELATION_SIGN_API_KEY:
claude mcp add relation-sign --scope user \
  -e RELATION_SIGN_API_KEY=rs_live_... \
  -- relation-sign-mcp
  1. 4Start agenten på nytt i en mappe med PDF-en, og skriv for eksempel «send kontrakt.pdf til Daniel for signering».

Finner ikke agenten programmet, bruk hele stien fra which relation-sign-mcp i stedet for bare navnet.

Hva agenten kan gjøre

Sende
Alle valgene fra «Ny signering»: kopimottakere, lesetilgang, kommentarer av eller på, konfidensiell med innsyn, påminnelser, mappe, arkiv i SharePoint og referanse. Den kan også lage utkast, og sende til deg så du signerer selv rett fra chatten.
Følge opp
Status per signatar, purring, lengre frist og avbryting, som du må bekrefte først.
Dokumentmaler
Fylle ut maler som samboeravtale eller leiekontrakt, spørre om det som mangler og lage et utkast du sier ja til før det sendes. Den kan også lage en egen mal av et dokument du har.
Kommentarer og dokumenter
Lese kommentarene og svare på dem, og laste ned den forseglede PDF-en.
Holde orden
Kontakter, Signatarsett, Meldingsmaler, mapper, godkjente signatarer og hurtigsignering.
Administratorer
Brukere, innstillingene for organisasjonen og forbruket.

Agenten får et lite sett med verktøy som standard. Mapper, kontakter, hurtigsignering, SharePoint og administrasjon slår du på når du trenger dem, eller agenten gjør det for deg når du ber om noe der.

Sikkerhet

  • Den personlige nøkkelen er deg. Agenten ser og gjør bare det du kan i appen, og alt sendes som deg.
  • Ingenting sendes uten ditt ja. Bekreftelsen gjelder bare akkurat den oppsummeringen du så, og et nytt forsøk sender ikke to ganger. Kommentarer og avbryting krever også et ja.
  • Blir du deaktivert, slutter nøkkelen å virke med en gang. Du kan tilbakekalle den under Min profil, og en administrator ser og kan tilbakekalle alle personlige nøkler under Integrasjoner.
  • Serveren kjører på maskinen der agenten kjører, og leser PDF-en derfra.

Planer og agenter

MCP bruker API-et og følger samme regel: gratis i Bedrift, Konsern og Relation OS. På Løs vekt trenger dere API-tillegget, 290 kr i måneden.

Virker med AI-agenter som støtter MCP over stdio: Claude Code, Hermes, Cursor, Codex, Claude Desktop og andre.

Signeringer

Opprette, sende, avbryte og hente signeringer.

GET/envelopes

Liste signeringer

Nyeste først, maks 500. Arkiverte signeringer er ikke med som standard. Slår dere opp på externalRef for å finne status, bruk archived=all.

Parametere

externalRefi adressen
stringBare signeringer med denne referansen.
statusi adressen
draft | sent | completed | declined | expired | cancelled | withdrawn
archivedi adressen
false | true | allfalse (standard) uten de arkiverte, true bare de arkiverte, all begge.
folderIdi adressen
stringEn mappe-id (bare signeringer rett i mappen), none (uten mappe) eller archived (i arkiverte mapper).
subfoldersi adressen
booleanMed folderId som mappe-id, også signeringene i mappene under.

Svar

200
Signeringene.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -G -H "Authorization: Bearer $RS_KEY" "$RS/envelopes" \
  --data-urlencode "externalRef=relation-os:stalbygg:change_order:7f3c" \
  --data-urlencode "archived=all"
POST/envelopes

Opprette en signering

Enten multipart/form-data med feltene file (PDF) og payload (JSON), eller application/json med PDF-en som fileBase64. Maks 25 MB PDF. Med send: true sendes signeringen med en gang; feiler sendingen, opprettes ingenting. Krever en nøkkel med full tilgang.

Parametere

Idempotency-Keyheader
stringSamme nøkkel og samme forespørsel innen 24 timer gir samme signering (eller, for POST /document-templates, samme mal) tilbake. Samme nøkkel med en annen forespørsel, også på en annen rute, gir 422; mens den første pågår, gir et nytt forsøk 409.

Kroppen er multipart/form-data eller application/json.

Svar

201
Signeringen er opprettet (og sendt med send). Med en gjentatt Idempotency-Key kommer samme signering tilbake med headeren Idempotent-Replayed: true.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
415
Bruk multipart/form-data eller application/json.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl, multipart
curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" \
  -H "Idempotency-Key: em-12-rev3" \
  -F file=@endringsmelding.pdf \
  -F 'payload={"title":"Endringsmelding EM-12","expiresInDays":14,"send":true,
      "externalRef":"relation-os:stalbygg:change_order:7f3c","senderEmail":"pl@straye.no",
      "signers":[{"name":"Kari Kunde","email":"kari@kunde.no","method":"bankid"}]}'
curl, JSON
curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"title\":\"Kontrakt\",\"signers\":[{\"name\":\"Ola\",\"email\":\"ola@ue.no\",\"method\":\"otp_email\"}],
       \"fileBase64\":\"$(base64 < kontrakt.pdf | tr -d '\n')\"}"
GET/envelopes/{id}

Hente en signering

Svarer alltid, arkivert eller ikke.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Signeringen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID"
PATCH/envelopes/{id}

Endre et utkast

Endrer tittelen og innstillingene til et utkast, for eksempel et utkast fra en mal (POST /document-templates/{ref}/fill), før det sendes, og hvem av signatarene som betaler (signers). Felt som ikke er med, beholder det utkastet har; dokumentet, kopimottakerne, lesetilgangen og signatarene, utenom hvem som betaler, endres ikke her. Samme regler som når utkastet endres i appen: en signering nøkkelen ikke ser, også i en annen organisasjon, gir 404 (en personlig nøkkel ser det eieren ser: en avsender sine egne og dem hen har innsyn i), en signering som ikke lenger er et utkast 409, og utkastet slik det blir sjekkes som en ny signering (422). Et felt ruten ikke kjenner, eller noe etter objektet, gir 400, så ingenting forsvinner i stillhet. En nøkkel fra Integrasjoner eller en tilkobling kan bare gjøre utkast den har laget selv konfidensielle (422 confidential_not_own), som med POST /envelopes: den ser bare de konfidensielle den har laget. Er endringen lagret, men nøkkelen ser ikke lenger utkastet (for eksempel når en med innsyn tar seg selv av listen), er svaret 200 med DraftOutOfSight, ikke 404. Signatarer som betaler (pays), beholder det til signers sier noe annet, og hvem som betaler, endrer aldri attachSignedPdf. Malens egne parter betaler som malen sier (422 pays_template_role). Et utkast der noen betaler, kan ikke gjøres konfidensielt (422 pays_not_confidential), og pays: true gir 422 pays_no_receipt på en signatar med delivery: none og receipt: false. En kopi av en signering laget fra en mal er en vanlig PDF-signering, så der kan hvem som betaler, endres. expiresInDays må være 1–180 (0 gir 422; på POST /envelopes betyr 0 standardfristen). Ruten tar ikke Idempotency-Key: samme endring to ganger gir samme utkast. Høyst 60 i minuttet per nøkkel. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

200
Utkastet slik det er nå, eller (lagret, men ute av syne) DraftOutOfSight.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X PATCH "$RS/envelopes/$ID" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "Les gjennom før du signerer.", "expiresInDays": 14, "folderId": null}'
POST/envelopes/{id}/send

Sende et utkast

Bare utkast (draft), ellers 409. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Signeringen er sendt.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/send"
POST/envelopes/{id}/cancel

Avbryte en signering

Bare sent, og ikke når alle har signert (forsegling pågår). Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Signeringen er avbrutt.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/cancel"
POST/envelopes/{id}/remind

Purre

Sender invitasjonen på nytt til alle som har tur og ikke har signert. Den som har fått e-post de siste ti minuttene, hoppes over. Bare sent, ellers 409. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Hvor mange som fikk påminnelse, hvem som ble hoppet over, og signeringen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/remind"
PATCH/envelopes/{id}/signers/{signerId}

Rette en signatar

Retter navn, e-post, telefon, signeringsmåte, språk eller fødselsdato for en signatar som ikke har signert ennå. Bare feltene som er med, endres. Ny e-postadresse gir en ny lenke, og den gamle slutter å virke. Bare draft og sent; en signatar som har signert eller avvist, gir 409. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.
signerIdi stien, påkrevd
stringSignatarens id, fra signers[].id på signeringen.

Kroppen er application/json.

Svar

200
Signeringen med den rettede signataren.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Valideringsfeil; meldingen sier hva.
curl
curl -X PATCH -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" \
  -d '{"email":"kari.nordmann@kunde.no"}' "$RS/envelopes/$ID/signers/$SIGNER"
POST/envelopes/{id}/signers/{signerId}/remind

Purre én signatar

Sender invitasjonen på nytt til én signatar som har tur og ikke har signert. Har signataren fått e-post de siste ti minuttene, gir det 429 med code: "too_soon". Bare sent, ellers 409. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.
signerIdi stien, påkrevd
stringSignatarens id, fra signers[].id på signeringen.

Svar

200
Signeringen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/signers/$SIGNER/remind"
GET/envelopes/{id}/signers/{signerId}/qr

QR-kode for signering på stedet

For en signatar med method: drawn (hurtigsignering): lenken som skal vises som QR-kode på arbeiderens skjerm. Den som skal signere, skanner den med sin egen telefon og signerer med fingeren. Koden byttes hvert 20. sekund; hent en ny når refreshInMs har gått. url er tom når signeringen er ferdig. scan viser siste skanning med en tosifret kontrollkode som også står på signatarens skjerm.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.
signerIdi stien, påkrevd
stringSignatarens id, fra signers[].id på signeringen.

Svar

200
Gjeldende kode.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/signers/$SIGNER/qr"
GET/envelopes/{id}/signers/{signerId}/signature

Den tegnede signaturen

PNG-bildet en signatar med method: drawn tegnet med fingeren. 404 før signataren har signert. Det samme bildet står på signatursiden og ligger som vedlegg i den forseglede PDF-en.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.
signerIdi stien, påkrevd
stringSignatarens id, fra signers[].id på signeringen.

Svar

200
Signaturen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -X GET -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/{id}/signers/{signerId}/signature"
POST/envelopes/{id}/archive

Arkivere en signering

Flytter signeringen ut av lista. Den er ikke borte, og kan hentes med archived=only eller archived=all. En signering som venter på signaturer (sent), må avbrytes først, ellers 422. Er den allerede arkivert, skjer ingenting. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Den arkiverte signeringen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/archive"
POST/envelopes/{id}/restore

Hente tilbake en arkivert signering

Legger signeringen tilbake i lista. Krever en nøkkel med full tilgang.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Signeringen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/restore"
GET/envelopes/{id}/comments

Kommentarer

Kommentarene på signeringen, eldste først, fra alle versjoner av dokumentet. En kommentar med page, x og y er festet til et sted i dokumentet; x og y er andeler av sidens bredde og høyde. parentId er kommentaren den svarer på.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Kommentarene.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/comments"
POST/envelopes/{id}/comments

Kommentere

En kommentar (eller et svar med parentId) fra eieren av en personlig nøkkel, som «Kommenter» i appen. Signatarene ser den. Bare med en personlig nøkkel; en API-nøkkel får 404. Signeringer der kommentarer er slått av, gir 409.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

201
Kommentaren.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Valideringsfeil; meldingen sier hva.
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/{id}/comments"

Dokumenter

Originalen, det forseglede dokumentet og bevisene.

GET/envelopes/{id}/sharepoint

Arkivering i SharePoint

Hvor det signerte dokumentet arkiveres i SharePoint (mode er default, own eller off) og hvordan opplastingen gikk. Bare med en personlig nøkkel, og bare for organisasjoner i piloten med SharePoint koblet til; ellers 404.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Valget og status.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -X GET -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/{id}/sharepoint"
PUT/envelopes/{id}/sharepoint

Velge arkivmappe i SharePoint

Som på «Ny signering»: standardmappen (default), ingen arkivering (off), eller en egen mappe (own med driveId og itemId fra GET /sharepoint/browse), som krever at eieren har koblet til sin egen Microsoft-konto i appen (409 microsoft_account_required ellers). Kan ikke endres når dokumentet er lastet opp (409).

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

200
Valget og status.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -X PUT -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/{id}/sharepoint"
GET/sharepoint

SharePoint-status

Om organisasjonen arkiverer i SharePoint, standardmappen, og om eieren av nøkkelen har koblet til sin egen Microsoft-konto. Bare med en personlig nøkkel og i piloten; ellers 404.

Svar

200
Status.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -X GET -H "Authorization: Bearer $RS_KEY" "$RS/sharepoint"
GET/sharepoint/browse

Bla i SharePoint

Nettsteder, biblioteker og mapper å velge fra, med eierens egen konto (as=me, standard) eller, for en administrator, organisasjonens (as=org). q søker; site, drive og item går ned i treet; next henter neste side. Bare med en personlig nøkkel og i piloten.

Parametere

asi adressen
me | org
qi adressen
string
sitei adressen
string
drivei adressen
string
itemi adressen
string
nexti adressen
string

Svar

200
Oppføringene.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -X GET -H "Authorization: Bearer $RS_KEY" "$RS/sharepoint/browse"
GET/envelopes/{id}/document

Originalen

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Originalen slik den ble lastet opp (siste versjon).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -H "Authorization: Bearer $RS_KEY" -o original.pdf "$RS/envelopes/$ID/document"
GET/envelopes/{id}/signed

Det forseglede dokumentet

Forseglet PDF med signaturside, original og evidence.json som vedlegg. Bare completed, ellers 409.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Den forseglede PDF-en.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -H "Authorization: Bearer $RS_KEY" -o signert.pdf "$RS/envelopes/$ID/signed"
GET/envelopes/{id}/evidence

Bevisene

evidence.json slik den ligger i den forseglede PDF-en (format: "relation-sign/evidence/v1"): signatarene med identitet og tidspunkt, hele hendelseskjeden med hasher, versjoner og kommentarer. Fødselsnummer er aldri med. Bare completed.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Bevisene.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/evidence"
GET/envelopes/{id}/evidence.zip

Bevispakken

En ZIP med signert.pdf, originalen av hver versjon (originaler/versjon-N.pdf), audit.pdf, evidence.json og README.txt om hvordan dokumentet kontrolleres. Bare completed, ellers 409. Høyst 30 i minuttet per nøkkel.

Parametere

idi stien, påkrevd
stringSigneringens id. En signering i en annen organisasjon gir 404.

Svar

200
Bevispakken.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -H "Authorization: Bearer $RS_KEY" -o bevispakke.zip "$RS/envelopes/$ID/evidence.zip"

Mapper

Organisasjonens mapper, for eksempel én per prosjekt.

GET/folders

Liste mapper

Dybde først, sortert på navn. count er signeringene rett i mappen og total med mappene under; arkiverte signeringer telles ikke. Arkiverte mapper er bare med når archived=true.

Parametere

archivedi adressen
boolean

Svar

200
Mappetreet.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/folders"
POST/folders

Opprette en mappe

Finnes det allerede en mappe med samme externalRef, svarer kallet 200 med den, så det er trygt å prøve igjen. Et navn som er tatt på samme sted gir 409. Krever en nøkkel med full tilgang.

Kroppen er application/json.

Svar

200
Mappen med denne externalRef fantes fra før.
201
Mappen er opprettet.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Valideringsfeil; meldingen sier hva.
curl
curl -X POST "$RS/folders" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"P42 Gressvik","kind":"project","externalRef":"relation-os:stalbygg:project:42"}'

Dokumentmaler

Fylle ut maler til utkast, og skrive egne maler i Markdown.

GET/document-templates

Liste malene som kan fylles ut

Organisasjonens egne maler som er publisert og ikke arkivert (etter navn), og så standardmalene for kontotypen i appens rekkefølge (et personlig arbeidsområde ser bare dem for privatpersoner og alle; en bedrift får kategoriene Avtaler, Arbeid og oppdrag og Selskap først). Med q kommer standardmalene som treffer best i navnet eller søkeordene først. q søker som biblioteket i appen: hvert ord i q må stå i navnet eller beskrivelsen til en egen mal, eller i navnet, sammendraget, loven, kategorien eller søkeordene (keywords) til en standardmal, uansett store og små bokstaver. Småord som «av», «og» og «for», og ord rundt et malsøk som «mal», «signering» og «pdf», telles ikke med når q har andre ord, så q=salg av bil finner «Salg av kjøretøy». Et helt ord i navnet eller et søkeord treffer best og kommer først.

Parametere

qi adressen
stringOver 200 tegn gir 400.

Svar

200
Malene.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates?q=samboer"
POST/document-templates

Lage en egen mal fra Markdown

Lager en egen mal som utkast, fra Markdown (formatet til standardmalene, se README) eller fra content som editoren lagrer det. Svaret sier hva som hindrer publisering (problems med linje) og hvilke spørsmål malen stiller. Kan ikke Markdown-en leses, eller bryter den reglene, lagres ingenting: 422 template_invalid med problems. Et navn som er tatt gir 409. Krever en nøkkel med full tilgang.

Parametere

Idempotency-Keyheader
stringSamme nøkkel og samme forespørsel innen 24 timer gir samme signering (eller, for POST /document-templates, samme mal) tilbake. Samme nøkkel med en annen forespørsel, også på en annen rute, gir 422; mens den første pågår, gir et nytt forsøk 409.

Kroppen er application/json.

Svar

201
Malen er lagret som utkast. Med en gjentatt Idempotency-Key kommer samme mal tilbake med Idempotent-Replayed: true.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Malen kan ikke lagres (code: "template_invalid"); problems sier hva, med linje i Markdown-en.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST "$RS/document-templates" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: parkering-v1" \
  --data "$(jq -Rs '{markdown: .}' parkering.md)"
POST/document-templates/validate

Sjekke en mal uten å lagre den

Leser Markdown (eller content) som POST /document-templates ville gjort, og lagrer ingenting. ok er true når malen kan publiseres og fylles ut. Hvert problem har severity: error (kan ikke lagres), not_ready (lagres som utkast, men kan ikke publiseres) eller note (stopper ingenting), og line når det kan sies. En lesenøkkel kan bruke den.

Kroppen er application/json.

Svar

200
Hva som er galt, og spørsmålene.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/validate"
GET/document-templates/{ref}

Malens spørsmål, eller Markdown-en

Spørsmålene i veiviserens rekkefølge, med når hvert spørres (shownWhen) og når det må besvares (requiredWhen), i ord og som vilkår; partene; summene; og «Før du begynner» (warnings). pinnedRef er versjonen spørsmålene gjelder (<id>@3): fyll ut den for å være sikker på at en ny versjon ikke kommer imellom. Et utkast (<id>@draft) har ingen pinnedRef: det endres ved hver lagring og fylles aldri ut. Med format=markdown kommer malen som Markdown (text/markdown) i stedet, en standardmal slik en egen mal ville hatt den; det Markdown ikke kan si, står som kommentarer øverst, og Relation-Sign-Markdown-Notes sier hvor mange. Med format=markdown-json kommer det samme som JSON: {ref, markdown, notes}, der notes er det Markdown ikke kan si (code: not_in_markdown, med path). format=markdown med Accept: application/json (og ikke text/markdown) gir også JSON-formen.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.
formati adressen
json | markdown | markdown-json

Svar

200
Malen.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/standard:samboer"
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/standard:samboer?format=markdown" -o samboer.md
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/standard:samboer?format=markdown-json"
PUT/document-templates/{ref}

Lagre utkastet til en egen mal

ref er malens id. Med Markdown byttes utkastet, navnet og beskrivelsen; med content utkastet, og name og summary når de er med. Hadde utkastet noe Markdown ikke kan si (bilder, understreking, justering …), er det borte etter en lagring med Markdown, og svaret sier det som note med code: lost_on_save; path peker da inn i utkastet slik det var før lagringen (det samme som notes fra <id>@draft?format=markdown-json før lagringen), ikke i det nye. Bare den som laget malen, eller en administrator, kan endre den (403). En standardmal gir 422 standard_template, en versjon 422 template_ref. Krever en nøkkel med full tilgang.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

200
Utkastet er lagret.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Malen kan ikke lagres (code: "template_invalid"); problems sier hva, med linje i Markdown-en.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X PUT -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/{ref}"
DELETE/document-templates/{ref}

Arkivere en egen mal

Malen forsvinner fra biblioteket og kan ikke fylles ut mer; signeringer laget fra den beholder det de ble laget fra. Det kan ikke angres, men den som kan endre malen, kan fortsatt hente utkastet (<id>@draft, også ?format=markdown) og lage en ny mal av det. Krever en nøkkel med full tilgang.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.

Svar

204
Arkivert.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
curl
curl -X DELETE -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/{ref}"
POST/document-templates/{ref}/publish

Publisere utkastet

Utkastet blir versjonen som fylles ut: 201 med en ny versjon, 200 når utkastet er versjonen som gjelder. Kan det ikke brukes ennå (ingen part som signerer, en henvisning som ikke stemmer, et tomt dokument), 422 template_not_ready med problems. Krever en nøkkel med full tilgang.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.

Svar

200
Utkastet er versjonen som gjelder.
201
En ny versjon.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/{ref}/publish"
POST/document-templates/{ref}/check

Sjekke svarene så langt

Serverens regler for en utfylling, uten PDF: hva som mangler (missing, i veiviserens rekkefølge med etikett og hvorfor), hva som er feil i det som er svart (fieldErrors), og spørsmålene svarene skjuler (hidden; de spørres ikke, og svarene på dem fjernes). ok er true når fill vil gå gjennom. «Dette er meg» (me: true på en part) er eieren av en personlig nøkkel, ellers avsenderen senderEmail gir. En lesenøkkel kan bruke den.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

200
Hva som mangler.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/{ref}/check"
POST/document-templates/{ref}/preview

Forhåndsvise PDF-en

PDF-en med svarene så langt; det som mangler står som «[Etikett]». Med sample: true fylles eksempelet inn der svar mangler. En standardmal har organisasjonens brevhode når den har ett, med mindre letterhead: false. Høyst 120 forhåndsvisninger i minuttet per nøkkel som ikke ligger i bufferen; over det 429 med retryAfter (sekunder). En lesenøkkel kan bruke den.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.

Kroppen er application/json.

Svar

200
PDF-en.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/{ref}/preview"
POST/document-templates/{ref}/fill

Fylle ut malen til et utkast

Lager PDF-en og et utkast til signering med partene som signerer som signatarer, og svarer som GET /envelopes/{id}. Det sendes med POST /envelopes/{id}/send. Uten title får signeringen navn fra malens titlePattern. Med envelopeId fylles et utkast laget fra samme mal på nytt («Endre svarene», 200; 409 når det ikke kan). En standardmal får organisasjonens brevhode, med mindre letterhead: false. Svar som ikke går gjennom gir 422 validation_failed med fieldErrors, som check sier på forhånd. Et utkast (@draft) kan ikke fylles ut (422 template_unpublished). Utkastets innstillinger kan gis med det samme, med navnene fra POST /envelopes: message, expiresInDays, signingOrder, reminders, confidential, viewerEmails og folderId (null: ingen mappe). De sjekkes med utkastet, så en innstilling som ikke går, gir 422 (eller 404 for en mappe nøkkelen ikke ser) uten at noe utkast lages; med envelopeId endres bare de som er med, og en nøkkel fra Integrasjoner kan bare gjøre utkast den har laget selv konfidensielle (422 confidential_not_own). En mal med en rolle som betaler, kan ikke fylles ut konfidensielt (422 pays_not_confidential), heller ikke på nytt i et utkast som er konfidensielt fra før (lag da en ny signering fra malen). Senere endres de med PATCH /envelopes/{id}. Høyst 20 i minuttet per nøkkel. Krever en nøkkel med full tilgang og samme avtale som POST /envelopes.

Parametere

refi stien, påkrevd
stringstandard:<slug>, malens id (versjonen som gjelder), <id>@<versjon> eller <id>@draft (utkastet, som kan leses, sjekkes og forhåndsvises, men ikke fylles ut). En mal i en annen organisasjon gir 404.
Idempotency-Keyheader
stringSamme nøkkel og samme forespørsel innen 24 timer gir samme signering (eller, for POST /document-templates, samme mal) tilbake. Samme nøkkel med en annen forespørsel, også på en annen rute, gir 422; mens den første pågår, gir et nytt forsøk 409.

Kroppen er application/json.

Svar

200
Utkastet envelopeId er fylt ut på nytt.
201
Utkastet er laget. Med en gjentatt Idempotency-Key kommer samme utkast tilbake med Idempotent-Replayed: true.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
409
Passer ikke med statusen, eller samme Idempotency-Key pågår.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X POST "$RS/document-templates/standard:samboer/fill" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: samboer-hauk-martine" \
  -d '{"values": {"fields": {"samboer_fra": "2024-08-01", "bolig": "Vi leier boligen",
       "bolig_adresse": "Bjerkeveien 12, 0480 Oslo", "leiekontrakt": {"other": "oss begge"},
       "utgifter": "Vi deler likt"},
       "parties": {"samboer": [{"me": true}, {"name": "Martine Berg", "email": "martine@example.no"}]}}}'
GET/brand

Merkevaren for dokumentene

Organisasjonens «Merkevare» for dokumentmaler: farger (#rrggbb), fonter, topptekst og bunntekst i tre deler med brikkene i chips, størrelser, vannmerke, forside, firmaopplysningene brikkene skriver, og om standardmalene tar farger, fonter og logostørrelse (standards). families er fontene som følger med, fonts organisasjonens egne. Egne maler bruker merkevaren, og malens appearance.brand kan overstyre hver gruppe (Markdown-hodet har den samme).

Svar

200
Merkevaren.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -X GET -H "Authorization: Bearer $RS_KEY" "$RS/brand"
PUT/brand

Endre merkevaren

Det som sendes, legges oppå merkevaren slik den er: et felt som ikke er med, blir stående, og null fjerner en gruppe. Tekstfargen må ha kontrast minst 4,5:1 mot hvitt og hovedfargen minst 3:1 (422 brand_contrast); noe annet som ikke passer er 422 brand_invalid. En font som verken følger med eller er organisasjonens egen, er 404. Krever en nøkkel med full tilgang (403 read_only_key ellers), og en personlig nøkkel må kunne administrere organisasjonen (403 admin_key_required); en tilkobling kan ikke (403 key_required). Høyst 30 i minuttet per nøkkel.

Kroppen er application/json.

Svar

200
Merkevaren slik den er nå.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
422
Valideringsfeil; meldingen sier hva.
429
For mange forespørsler (300 i minuttet per nøkkel, 60 opprettelser i minuttet).
curl
curl -X PUT "$RS/brand" -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" \
  -d '{"colors": {"primary": "#1f4d3a", "accent": "#c8a24a"}, "fonts": {"body": "Charis SIL"},
       "footer": {"left": "{firma}", "right": "{side}"}, "watermark": "KONFIDENSIELT"}'

Konto

Hvem nøkkelen eller tilkoblingen gjelder.

GET/me

Hvem nøkkelen gjelder

Organisasjonen og tilkoblingen (OAuth), eller den personlige nøkkelen og eieren. Zapier og Make bruker kallet til å teste og navngi kontoen, MCP-serveren til å si hvem den kjører som. Krever ingen bestemt tilgang. En API-nøkkel fra Integrasjoner får 404.

Svar

200
Organisasjonen og legitimasjonen.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/me"
GET/contacts

Finne en person å sende til

Organisasjonens «Kontakter» (mest brukt først), deretter aktive kolleger som ikke står der. q søker i navn og e-post (og telefon for kontakter). Brukes av MCP-serveren til å finne ut hvem «Daniel» er. method er metoden kontakten sist signerte med, når den er kjent.

Parametere

qi adressen
string
limiti adressen
integer

Svar

200
Treffene.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
curl
curl -H "Authorization: Bearer $RS_KEY" "$RS/contacts?q=daniel"

Webhooker

Abonnere på hendelser fra API-et (REST hooks), for Zapier, Make og lignende.

POST/webhooks

Abonnere på hendelser

Lager en webhook som får hendelsene i events (tom eller manglende: alle). Hemmeligheten vises bare her. En tilkobling trenger tilgangen webhooks; webhooken hører til tilkoblingen, teller ikke mot organisasjonens ti og slettes når tilkoblingen kobles fra (høyst 20 per tilkobling). En API-nøkkel får 404; webhooker for nøkler lages i appen.

Kroppen er application/json.

Svar

201
Webhooken er laget.
400
Ugyldig forespørsel (JSON, filter).
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
422
Valideringsfeil; meldingen sier hva.
curl
curl -X POST "$RS/webhooks" -H "Authorization: Bearer $RS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.zapier.com/...","events":["envelope.completed"]}'
DELETE/webhooks/{id}

Avslutte et abonnement

En tilkobling kan bare slette sine egne webhooker; andre gir 404.

Parametere

idi stien, påkrevd
string

Svar

204
Slettet.
401
Nøkkelen mangler, er ukjent, utløpt eller tilbakekalt.
403
Planen har ikke API, avtalen er ikke godtatt, eller nøkkelen kan bare lese (code: "read_only_key").
404
Finnes ikke i organisasjonen til nøkkelen.
curl
curl -X DELETE -H "Authorization: Bearer $RS_KEY" "$RS/webhooks/{id}"

Beskrivelse

Denne beskrivelsen.

GET/openapi.yaml

Denne beskrivelsen

OpenAPI 3.1 for API-et, uten nøkkel.

Trenger ingen nøkkel.

Svar

200
Denne filen.
curl
curl -o relation-sign.yaml "$RS/openapi.yaml"

Sjekk at en webhook kommer fra oss

Hver melding har headeren Relation-Sign-Signature: t=…,v1=…. v1 er HMAC-SHA256 med hemmeligheten over <t>.<rå kropp>. Sjekk den rå kroppen før du parser den, og avvis meldinger der t er mer enn fem minutter fra nå.

I 24 timer etter at hemmeligheten er byttet, har headeren to v1. Godta meldingen hvis én av dem stemmer, slik eksemplene gjør.

package relationsign

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// VerifyRequest reads the body and checks Relation-Sign-Signature.
func VerifyRequest(r *http.Request, secret string) ([]byte, error) {
	body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
	if err != nil {
		return nil, err
	}
	var ts string
	var sigs []string
	for _, part := range strings.Split(r.Header.Get("Relation-Sign-Signature"), ",") {
		k, v, _ := strings.Cut(strings.TrimSpace(part), "=")
		switch k {
		case "t":
			ts = v
		case "v1":
			sigs = append(sigs, v)
		}
	}
	sec, err := strconv.ParseInt(ts, 10, 64)
	if err != nil {
		return nil, errors.New("missing timestamp")
	}
	if d := time.Since(time.Unix(sec, 0)); d > 5*time.Minute || d < -5*time.Minute {
		return nil, errors.New("timestamp outside tolerance")
	}
	m := hmac.New(sha256.New, []byte(secret))
	m.Write([]byte(ts + "."))
	m.Write(body)
	want := hex.EncodeToString(m.Sum(nil))
	for _, s := range sigs {
		if hmac.Equal([]byte(s), []byte(want)) {
			return body, nil
		}
	}
	return nil, errors.New("signature does not match")
}

Hele veiledningen

Idempotens, lesetilgang, webhookene og administrasjonen i detalj, fra docs/api/README.md.

Status: gjeldende (25.10.2026).

API-et lar et annet system, for eksempel Relation OS, sende PDF-dokumenter til signering, følge med på statusen og hente det signerte dokumentet. Alle svar er JSON med camelCase, bortsett fra PDF-nedlastingene. Feil har formen { "error": "melding", "code": "maskinkode" }. Meldingen er på norsk og kan vises brukeren, men kan endres; test på code, som er stabil. Koder følger ellers statusen: bad_request, unauthorized, forbidden, not_found, method_not_allowed, conflict, gone, payload_too_large, validation_failed, rate_limited, internal, i tillegg til mer spesifikke som agreement_required, already_signed, hash_mismatch, locked, too_soon, folder_not_found, organization_suspended og verify_required. Også ukjente stier (404) og feil metode (405) svarer med denne formen.

Grunnadresse: https://<domene>/api/v1 (lokalt http://localhost:8090/api/v1).

Maskinlesbar beskrivelse: OpenAPI 3.1 i docs/api/openapi.yaml, servert uten nøkkel på GET /api/v1/openapi.yaml. En test sjekker at hver rute under /api/v1 står i filen og omvendt.

Autentisering

En administrator lager en API-nøkkel i Relation Sign (Integrasjoner, API-nøkler, eller POST /api/api-keys). Nøkkelen vises én gang; Relation Sign lagrer bare SHA-256 av den. Nøkler i produksjon starter med rs_live_, i utvikling med rs_test_.

export RS=https://sign.relationlabs.no/api/v1
export RS_KEY=rs_live_...
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes"
  • API-et krever en plan med API: Bedrift, Konsern, Relation OS og Intern har det med, Løs vekt bare med API-tillegget. Uten gir en gyldig nøkkel 403 med en melding om planen, nye nøkler og webhooker kan ikke lages (403), og webhooker sendes ikke (se «Planer, tilgang og forbruk» i docs/specs/2026-10-18-relation-sign-mvp-design.md).
  • Manglende, ukjent, utløpt eller tilbakekalt nøkkel gir 401.
  • En nøkkel har tilgangen full (standard) eller bare lese (scope: "read"). En lesenøkkel kan bare gjøre GET, og tørrkjøringene for dokumentmaler som ikke endrer noe (validate, check, preview); alt annet gir 403 med code: "read_only_key". Tilgangen settes når nøkkelen lages og kan ikke endres; lag en ny nøkkel i stedet.
  • En nøkkel kan ha en utløpsdato (expiresAt, innen tre år). Etter den gir den 401 med meldingen «API-nøkkelen er utløpt».
  • Integrasjoner viser når og fra hvilken IP-adresse hver nøkkel sist ble brukt, og hvem som laget den.
  • Nøkkelen gjelder én organisasjon. En signering i en annen organisasjon gir 404, aldri 403.
  • Nøkkelen ser alle signeringer i organisasjonen.
  • En personlig nøkkel (se under) ser bare det eieren ser.
  • Grenser per nøkkel: 300 forespørsler i minuttet, og 60 opprettelser i minuttet. Over grensen kommer 429.
Kode Betyr
400 ugyldig forespørsel (JSON, status-filter)
401 nøkkel mangler eller er ugyldig
403 planen til organisasjonen har ikke API (Løs vekt uten API-tillegget), nøkkelen kan bare lese (code: "read_only_key"), eller Relation Labs har suspendert organisasjonen (code: "organization_suspended": organisasjonen er helt blokkert, og alle kall med nøkkelen avvises, lesing som skriving, til suspensjonen er opphevet; webhook-leveranser blir stående i køen)
404 finnes ikke i din organisasjon
409 passer ikke med statusen (for eksempel sende noe som er sendt), eller samme Idempotency-Key pågår
415 feil Content-Type
422 valideringsfeil, meldingen sier hva
429 for mange forespørsler

Personlige nøkler

En personlig nøkkel lager hver bruker selv under Min profil, for sin egen AI-agent (MCP-serveren i docs/mcp.md). Den har samme form og de samme grensene som en vanlig nøkkel, med disse forskjellene:

  • Den er eieren: den ser og gjør bare det eieren kan i appen. En avsender ser sine egne signeringer og de konfidensielle hen har innsyn i; alle andre gir 404. En administrator ser det administratoren ser.
  • Rollekravene i appen gjelder: en avsender ser navnene på godkjente signatarer, men ikke telefon, e-post eller fødselsdato, og folder på POST /envelopes gjenoppretter ikke en arkivert mappe (409) og tar ikke over en mappe en annen har laget.
  • Den sender alltid som eieren. senderEmail kan utelates eller være eierens adresse; en annen gir 422 med code: "personal_key".
  • Den slutter å virke (401) når eieren deaktiveres eller fjernes fra organisasjonen, og en endret rolle gjelder fra neste kall.
  • Den krever en plan med API, som andre nøkler.
  • Revisjonssporet viser « via personlig nøkkel «»».
  • GET /me svarer med nøkkelen og eieren (user: { id, name, email, role }).

Personlig nøkkel på appens egne ruter

En personlig nøkkel kan også brukes på en eksplisitt liste med appens egne ruter under /api (ikke /api/v1), som en innlogget økt for eieren i nøkkelens organisasjon. Det er dette MCP-serveren bruker for alt som ikke er i /api/v1: kontakter, signatarsett, meldingsmaler, mapper, godkjente signatarer, håndtering av signeringer, og for administratorer brukere, organisasjonsinnstillinger, plan og forbruk. Listen står i internal/httpapi/personal_bridge.go; rutenes egne rollekrav gjelder (403 for en avsender på en administratorrute, 404 for andres signeringer).

  • Administrasjon (brukere, godkjente signatarer og innstillingene for dem, standard påminnelser, plan, moduler, logo, SharePoint-standardmappe) krever i tillegg tilgangen admin på nøkkelen (403 admin_key_required ellers). Bare en administrator kan lage en slik nøkkel, i nettleseren. Det samme gjelder skriving av godkjente signatarer i /api/v1.
  • Ruter som gir rett til å signere (QR-koden for hurtigsignering) er stengt for lesenøkler, selv om de er GET.
  • Godkjenning av koblingsforespørsler fra Relation OS gjøres aldri med nøkkel.
  • Alt som ikke står på listen gir 403 med code: "personal_key_not_allowed", også for en administrator: innlogging, nøkler, passkeys, webhooks, tilkoblinger, avtaler, bytte av organisasjon, og å koble til eller fra Microsoft-kontoer.
  • En API-nøkkel fra Integrasjoner gir 403 med code: "personal_key_required".
  • En lesenøkkel kan bare gjøre GET (403 read_only_key), planregelen for API gjelder, og revisjonssporet viser nøkkelen.
  • Rutene er appens interne grensesnitt og kan endres uten varsel. For egne integrasjoner: bruk /api/v1.

Finne en person: GET /contacts?q=&limit=

Organisasjonens «Kontakter» (mest brukt først), deretter aktive kolleger som ikke står der: { contacts: [{ name, email, phone, method, source }] }, der source er contact eller colleague og method er metoden kontakten sist signerte med (eller null). q søker i navn, e-post og telefon; limit er 1 til 100, standard 20. Brukes til å finne ut hvem «Daniel» er.

Signeringer

Opprette: POST /envelopes

Enten multipart/form-data med feltene file (PDF) og payload (JSON), eller application/json med PDF-en som fileBase64. Maks 25 MB PDF.

Felt Type
title streng, påkrevd maks 200 tegn
message streng til signatarene, maks 4000 tegn
signingOrder parallel (standard) eller sequential fast rekkefølge varsler én og én
expiresInDays 1 til 180, standard 7 regnes fra sending
signers 1 til 20 { name, email, phone?, method, birthDate?, pays?, delivery?, returnUrl?, receipt? }, method er bankid, otp_email eller otp_sms (krever phone). birthDate (ÅÅÅÅ-MM-DD, valgfri, bare BankID): fødselsdatoen i BankID avgjør da hvem som kan signere. pays (valgfri, standard false): signataren er en forbruker som skal betale, se Signatar som betaler. delivery, returnUrl og receipt: se Innebygd signering.
externalRef streng, maks 200 din referanse, for eksempel relation-os:stalbygg:change_order:<id>; ikke unik
readAccess link (standard), email_code, sms_code eller bankid lesetilgang: hva signataren må gjøre før dokumentet vises, se under. sms_code krever phone på alle signatarene
allowComments true (standard) eller false om signatarene kan kommentere i dokumentet. Med false kan de bare signere eller avvise (med begrunnelse), og ingen kan kommentere, heller ikke dere. Kan endres mens signeringen er et utkast
attachSignedPdf true eller false, standard organisasjonens innstilling legger den signerte PDF-en ved e-postene alle får når alle har signert, i tillegg til lenken. Bare med readAccess link eller email_code og ikke konfidensiell; true ellers gir 422 attach_not_allowed. Se Signert PDF som vedlegg. Kan endres mens signeringen er et utkast
theme dark (standard) eller light utseendet på siden signatarene og kopimottakerne åpner. Alle får det samme; hver mottaker kan likevel bytte på sin egen enhet. Kan endres mens signeringen er et utkast
confidential true eller false (standard) konfidensiell signering: synlig bare for nøkkelen som laget den, og i appen for avsenderen og personene i viewerEmails. Andre nøkler får 404, administratorer ser den bare som et tall. Kan ikke slås av igjen. Se Konfidensielle signeringer
viewerEmails liste med e-post, maks 50 bare med confidential: true: aktive brukere i organisasjonen som skal kunne åpne den i appen, i tillegg til avsenderen. En adresse som ikke er en aktiv bruker gir 422
reminders se under, standard organisasjonens innstilling automatiske påminnelser til signatarer som ikke har signert
send bool, standard false true sender med en gang; feiler sendingen, opprettes ingenting
senderEmail streng gjør denne brukeren til avsender hvis hen er en aktiv bruker i organisasjonen. Ellers, i rekkefølge: nøkkelens reserveavsender (satt under Integrasjoner), den som laget nøkkelen, organisasjonens eldste aktive administrator. Deaktiverte brukere hoppes over; finnes ingen aktiv bruker, gir kallet 422
fileBase64 streng bare for JSON
folderId uuid legger signeringen i en av organisasjonens mapper (se Mapper); en ukjent mappe gir 404, en arkivert 409
folder { externalRef, name } finner mappen med denne externalRef, eller lager den øverst med name første gang (se Mapper). Ikke sammen med folderId (422)

Header Idempotency-Key (valgfri, maks 200 tegn): se under.

# multipart
curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" \
  -H "Idempotency-Key: em-12-rev3" \
  -F file=@endringsmelding.pdf \
  -F 'payload={"title":"Endringsmelding EM-12","signingOrder":"parallel","expiresInDays":14,
      "externalRef":"relation-os:stalbygg:change_order:7f3c","senderEmail":"pl@straye.no","send":true,
      "signers":[{"name":"Kari Kunde","email":"kari@kunde.no","method":"bankid"}]}'

# JSON
curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" \
  -d "{\"title\":\"Kontrakt\",\"send\":false,\"signers\":[{\"name\":\"Ola\",\"email\":\"ola@ue.no\",\"method\":\"otp_email\"}],
       \"fileBase64\":\"$(base64 < kontrakt.pdf | tr -d '\n')\"}"

Svar 201 med en Envelope:

{
  "id": "1b7c...",
  "title": "Endringsmelding EM-12",
  "status": "sent",
  "signingOrder": "parallel",
  "createdAt": "2026-10-19T08:00:00Z",
  "sentAt": "2026-10-19T08:00:00Z",
  "completedAt": null,
  "expiresAt": "2026-11-02T08:00:00Z",
  "externalRef": "relation-os:stalbygg:change_order:7f3c",
  "createdBy": { "id": "…", "name": "Per Prosjektleder" },
  "message": "",
  "originalSha256": "9f2a…",
  "originalPages": 3,
  "originalSize": 182044,
  "sealedSha256": null,
  "version": 1,
  "versions": [{ "version": 1, "sha256": "9f2a…", "pages": 3, "size": 182044, "by": "", "createdAt": "…" }],
  "signers": [{
    "id": "…", "position": 1, "name": "Kari Kunde", "email": "kari@kunde.no", "phone": "",
    "method": "bankid", "status": "notified", "notifiedAt": "…", "viewedAt": null, "signedAt": null,
    "declinedAt": null, "declineReason": "", "signedName": "", "signedBirthDate": "", "nameMismatch": false,
    "birthDate": "", "identityMatch": "",
    "withdrawnAt": null, "withdrawReason": "", "invalidatedAt": null, "invalidatedReason": "",
    "delivery": "email", "returnUrl": "", "receipt": true, "appName": ""
  }],
  "events": [{ "id": "…", "type": "sent", "signerName": "", "createdAt": "…", "ip": "…", "data": {} }],
  "mySigningPath": null,
  "readAccess": "link",
  "reminders": { "mode": "standard", "days": [3, 7], "beforeDeadlineDays": 2 },
  "archivedAt": null,
  "archiveReason": null,
  "folderId": "5d0e…",
  "folder": { "id": "5d0e…", "name": "P42 Gressvik", "color": null, "kind": "project", "archived": false }
}

Statuser: signering draft, sent, completed, declined, expired, cancelled, withdrawn. Signatar pending, notified, viewed, signed, declined, withdrawn.

archivedAt er satt når signeringen ligger i arkivet, og archiveReason er da manual eller auto. Arkivet er bare en visning hos avsenderen: ingenting er slettet, status er uendret, dokumentene kan hentes som før og lenkene til signatarer og kopimottakere virker. Ferdige signeringer arkiveres automatisk 30 dager etter at de ble avsluttet. Arkivering, henting fra arkivet og permanent sletting gjøres i Relation Sign, ikke gjennom API-et.

Påminnelser

reminders styrer de automatiske påminnelsene. Uten feltet får signeringen organisasjonens standard, som en administrator setter under Organisasjon (fra start: dag 3 og 7, og 2 dager før fristen).

mode Påminnelser
off ingen automatiske påminnelser
standard dag 3 og 7 etter invitasjonen
custom dagene i days: 1 til 5 dager, hver mellom 1 og 60

beforeDeadlineDays (0 til 14, standard 2) sender én påminnelse til så mange dager før fristen; 0 slår den av. Dager regnes i norsk tid. Bare signatarer som har fått lenken, ikke har signert og har tur (fast rekkefølge), får påminnelser, og aldri to e-poster samme døgn. Avsenderen får uansett et varsel dagen før fristen når noen ikke har signert.

"reminders": { "mode": "custom", "days": [2, 5, 10], "beforeDeadlineDays": 1 }

Kortformer: "reminders": "off", "reminders": "standard" eller en liste med dager, "reminders": [2, 5] (custom). Svaret viser alltid hele objektet; standard viser days: [3, 7].

Lesetilgang og bekreftelse

Lenken alene lar signataren lese dokumentet (readAccess: "link"). Med en annen readAccess må signataren bekrefte at det er dem før tittel, dokument, kommentarer og signert PDF vises; til da viser signeringssiden bare hvem den er fra, fornavnet, fristen og hvor koden går:

readAccess Bekreftelse før lesing Forbruk
link ingen ingenting
email_code sekssifret kode på e-post gratis, ingen rad i forbruket
sms_code sekssifret kode på SMS hver SMS teller, også koder som sendes på nytt
bankid innlogging med eID: norsk eller svensk BankID, dansk MitID, finsk eID eller Vipps, det som er slått på (navnet sjekkes mot signataren) hver innlogging teller som én eID-bruk (BankID, MitID, finsk eID eller Vipps), også når den blir avbrutt eller feiler; samme pris for alle eID-er, og den trekker fra eID-bruken som er med i planen

Uansett readAccess krever det å avvise, kommentere (og svare) og trekke en signatur at signataren har bekreftet at det er dem: en kode på e-post (gratis; uten e-postadresse på SMS, der hver SMS teller). Bekreftelsen gjelder i to timer i nettleseren den ble gjort i. Selve signeringen er uendret: BankID eller engangskode i signeringsøyeblikket, bundet til dokumentet, også når signataren logget inn med BankID for å lese.

Kopimottakere og signatarer som henter den signerte PDF-en, må bekrefte med en kode på e-post når signeringen har vært fullført i mer enn 30 dager. For kopimottakere gjelder det fra første dag når readAccess ikke er link. Bekreftelsene står i hendelsesloggen og revisjonsloggen (access_code_sent, access_code_failed, access_verified, access_rejected, aldri selve koden), men sendes ikke som webhooker.

Signert PDF som vedlegg

Når alle har signert, får avsenderen, signatarene og kopimottakerne en e-post med lenke til det forseglede dokumentet i Relation Sign. Med attachSignedPdf: true ligger den signerte PDF-en også ved e-posten, så hver mottaker har sin egen kopi.

Et vedlegg er like åpent som innboksen det havner i. Derfor går det bare der innboksen uansett er nøkkelen: lesetilgang link eller email_code. Med sms_code eller bankid har dere sagt at e-posten ikke er nok, og en konfidensiell signering er bare for avsenderen og personene med innsyn; der legges PDF-en aldri ved. Blir et utkast konfidensielt, eller får det en strengere lesetilgang, slås vedlegget av.

Uten attachSignedPdf gjelder organisasjonens innstilling (av, med mindre en administrator har slått den på i appen under «Organisasjon»). En PDF som er for stor til e-post (over omtrent 2,4 MB), sendes bare som lenke, og e-posten sier det. GET /envelopes/{id} viser valget som attachSignedPdf. I appen spør «Send til signering» om valget der det er tillatt.

Signatar som betaler: pays

En signatar med "pays": true er en forbruker som skal betale dere etter dokumentet, for eksempel en kjøpekontrakt, et tilbud eller en håndverkerkontrakt. Knappen på signeringssiden sier da «Signer med plikt til å betale» (angrerettloven § 16; på engelsk «Sign with obligation to pay», svensk «Signera med betalningsskyldighet», dansk «Signér med betalingsforpligtelse»), med en linje under om hvordan hen signerer.

Når alle har signert, legges den signerte PDF-en ved e-posten til signataren som betaler, uansett hva attachSignedPdf er. Alle andre, det vil si de andre signatarene, avsenderen og kopimottakerne, får den slik attachSignedPdf sier, og pays endrer aldri attachSignedPdf. To unntak gir bare lenken også til den som betaler, og e-posten sier det:

  • Lesetilgangen tillater ikke vedlegg (sms_code eller bankid). Med link eller email_code legges den ved.
  • Den signerte PDF-en er for stor til e-post (over omtrent 2,4 MB). Den inneholder dokumentet to ganger, som sider og som original.pdf, i tillegg til signatursiden og seglet. Det betyr at en opplastet PDF over omtrent 1 MB (1 000 000 byte) blir for stor, for eksempel en skannet kontrakt. Den signerte avtalen ligger da bak lenken i Relation Sign så lenge signeringen er lagret. Appen varsler om dette på signataren før dere sender.

Det gjelder en PDF dere laster opp, like mye som et dokument laget fra en mal.

curl -X POST "$RS/envelopes" -H "Authorization: Bearer $RS_KEY" \
  -F file=@kjopekontrakt.pdf \
  -F 'payload={"title":"Kjøpekontrakt","send":false,
      "signers":[{"name":"Kari Kunde","email":"kari@kunde.no","method":"bankid","pays":true}]}'
  • Ikke i en konfidensiell signering (422 pays_not_confidential), fordi den aldri sendes med vedlegg. Et utkast som er konfidensielt, kan ikke gjøres åpent igjen, så da må dere lage en ny signering.
  • Ikke for en signatar som signerer på stedet (method: drawn, 422 pays_not_drawn), fordi den knappen ikke sier at signaturen gir plikt til å betale.
  • Ikke for en signatar som ikke får e-posten når alle har signert, det vil si delivery: none med receipt: false (422 pays_no_receipt). Med receipt: true, eller uten delivery: none, går det.
  • I et utkast laget fra en mal bestemmer malen for sine egne parter (de med rolle fra malen). De betaler som rollen sier, uansett hva forespørselen sier, og PATCH gir 422 pays_template_role. En signatar som er lagt til for hånd, betaler når pays sier det. Bytter dere ut malens dokument med en annen PDF, betaler ikke malens roller lenger.
  • En kopi («Lag kopi» i appen, POST /envelopes/{id}/duplicate) betaler som originalen. En kopi av en signering laget fra en mal er ikke lenger malens: den er en vanlig PDF-signering, så dere kan endre hvem som betaler på kopien.
  • Et signatarsett lagrer aldri pays.
  • GET /envelopes/{id} viser det som signers[].pays.
  • Dokumentet er deres. Det er dere som sørger for at det sier hva signataren skal betale, og at det er riktig signatar som er merket.

Konfidensielle signeringer

Med confidential: true ser bare nøkkelen som laget signeringen den. En annen nøkkel i organisasjonen får 404 og finner den ikke i listen, og nøkkelen ser aldri en konfidensiell signering som er laget i appen. I appen kan avsenderen (senderEmail) og personene i viewerEmails åpne den, men ikke administratorene. Innsyn kan endres i appen etterpå. Det kan ikke gjøres om: confidential: false på et konfidensielt utkast gir 422. Webhooker sier hva som skjedde, ikke hva det gjelder: data.envelope har bare id, externalRef, status, signingOrder, version, tidspunktene og "confidential": true. data.signer og data.comment mangler. Hendelsene confidential_set, viewer_added og viewer_removed står i hendelsesloggen, men sendes ikke som webhooker.

Hente: GET /envelopes/{id}

curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID"

Svar 200 med Envelope.

Liste: GET /envelopes?externalRef=&status=&archived=&folderId=&subfolders=

curl -G -H "Authorization: Bearer $RS_KEY" "$RS/envelopes" \
  --data-urlencode "externalRef=relation-os:stalbygg:change_order:7f3c"

Svar { "envelopes": EnvelopeSummary[] }, nyeste først, maks 500. Arkiverte signeringer er ikke med som standard: archived=true gir bare de arkiverte, archived=all begge, archived=false (standard) de som ikke er arkivert; andre verdier gir 400. Slår dere opp på externalRef for å finne status, bruk archived=all, ellers forsvinner en signering fra svaret 30 dager etter at den ble avsluttet. GET /envelopes/{id} svarer alltid, arkivert eller ikke. folderId er en mappe-id (bare signeringer rett i mappen, med subfolders=true også i mappene under), none (uten mappe) eller archived (i en arkivert mappe); en ukjent mappe gir 404. EnvelopeSummary er Envelope uten message, hashene, events og versions, og med signers: [{ name, status }].

Endre et utkast: PATCH /envelopes/{id}

Tittelen og innstillingene til et utkast, for eksempel et utkast fra en mal, før det sendes, og hvem av signatarene som betaler. Bare feltene som er med, endres:

curl -X PATCH "$RS/envelopes/$ID" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Samboeravtale Hauk og Martine", "message": "Les gjennom før du signerer.",
       "expiresInDays": 14, "signingOrder": "sequential", "reminders": [3, 7],
       "confidential": true, "viewerEmails": ["anne@straye.no"], "folderId": null}'

curl -X PATCH "$RS/envelopes/$ID" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signers": [{"id": "'$SIGNER_ID'", "pays": true}]}'
Felt
title, message, expiresInDays, signingOrder, reminders som på POST /envelopes
confidential true gjør utkastet konfidensielt; false på et konfidensielt gir 422 (det kan ikke gjøres åpent igjen)
viewerEmails erstatter hvem som har innsyn i tillegg til avsenderen; [] gir bare avsenderen; på et åpent utkast 422
folderId mappen utkastet skal ligge i; null tar det ut av mappen
signers [{ id, pays }]: om signataren med denne id-en (fra signers[].id) betaler, se Signatar som betaler. Hver signatar høyst én gang, og pays må være med. En id utkastet ikke har, også id-en til en signatar i en annen signering, gir 422. Alle signatarene beholder id-ene sine, også ved siden av en som signerer på stedet

Svar 200 med Envelope. Reglene er de samme som når utkastet endres i appen: et utkast nøkkelen ikke ser, også i en annen organisasjon, gir 404 (en personlig nøkkel ser det eieren ser: en avsender sine egne og dem hen har innsyn i), en signering som ikke lenger er et utkast gir 409, og utkastet slik det blir, sjekkes som en ny signering (422). Dokumentet, kopimottakerne, lesetilgangen og signatarene, utenom hvem som betaler, endres ikke her, og et felt ruten ikke kjenner, eller noe etter JSON-objektet, gir 400 i stedet for å bli oversett. En lesenøkkel får 403 read_only_key.

  • En nøkkel fra Integrasjoner eller en tilkobling ser bare de konfidensielle signeringene den har laget selv, så den kan bare gjøre egne utkast konfidensielle (som med POST /envelopes); et annet gir 422 confidential_not_own, og ingenting endres.
  • Er endringen lagret, men nøkkelen ser ikke lenger utkastet (en med innsyn tok seg selv av listen), er svaret 200 med { id, status: "draft", confidential: true, visible: false, message }, ikke 404.
  • Den som betaler, beholder det til signers sier noe annet, og får den signerte PDF-en som vedlegg i sin egen e-post. attachSignedPdf endres ikke av hvem som betaler. Malens egne parter betaler som malen sier (422 pays_template_role hvis dere prøver å endre det).
  • Et utkast der noen betaler, kan ikke gjøres konfidensielt (422 pays_not_confidential), fordi en konfidensiell signering aldri sendes med vedlegg. Det gjelder også ved fill, og ved fill med envelopeId på et utkast som er konfidensielt fra før, når malen nå har en rolle som betaler.
  • pays: true gir 422 pays_no_receipt på en signatar med delivery: none og receipt: false.
  • expiresInDays må være 1–180 her og på fill; 0 gir 422. (På POST /envelopes betyr 0 standardfristen, 7 dager.)
  • Ruten tar ikke Idempotency-Key: samme endring to ganger gir samme utkast. Høyst 60 i minuttet per nøkkel.

Sende: POST /envelopes/{id}/send

Bare utkast (draft), ellers 409.

curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/send"

Avbryte: POST /envelopes/{id}/cancel

Bare sent, og ikke når alle har signert (forsegling pågår).

curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/cancel"

Purre: POST /envelopes/{id}/remind

Sender invitasjonen på nytt til alle som har tur og ikke har signert. Den som har fått e-post de siste ti minuttene, hoppes over. Bare sent, ellers 409.

curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/remind"
{ "reminded": 2, "throttled": ["Ola Hansen"], "envelope": { "id": "…", "…": "…" } }

Purre én signatar: POST /envelopes/{id}/signers/{signerId}/remind

Sender invitasjonen på nytt til én signatar som har tur. Har signataren fått e-post de siste ti minuttene, gir det 429 med code: "too_soon". Svarer med signeringen. signerId er signers[].id. En signatar med delivery: "none" får ikke e-post fra oss og gir 409 med code: "delivery_none"; «Purr alle» hopper over dem.

curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/signers/$SIGNER/remind"

Hente signeringslenken: POST /envelopes/{id}/signers/{signerId}/link

Gir lenken signataren fikk på e-post, så en integrasjon kan vise den til signataren selv, for eksempel en AI-assistent som sender en kontrakt til brukeren den snakker med og gir lenken i chatten. Bare når signataren har tur og ikke har signert, ellers 409; en signatar med method: drawn bruker QR-koden. Krever en nøkkel med full tilgang.

Lenken åpner bare signeringssiden. Selve signeringen krever fortsatt signatarens egen BankID (navnet sjekkes) eller en kode til signatarens egen e-post eller telefon, så den som henter lenken kan ikke signere for noen andre. readAccess gjelder som før. Hver henting står i hendelsesloggen (link_issued) med hvilken nøkkel som hentet den. Gi lenken bare til signataren den gjelder.

curl -X POST -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/signers/$SIGNER/link"
{ "url": "https://sign.relationlabs.no/s/…", "signerId": "…", "signerName": "Kari Kunde", "signerStatus": "notified", "method": "bankid" }

BankID kan ikke startes fra API-et: signataren åpner lenken og trykker «Signer med BankID». Si derfor «åpne lenken og signer med BankID», ikke «bekreft BankID på telefonen».

Rette en signatar: PATCH /envelopes/{id}/signers/{signerId}

Retter name, email, phone, method, locale eller birthDate for en signatar som ikke har signert ennå. Bare feltene som er med, endres. Ny e-postadresse gir en ny lenke, og den gamle slutter å virke. En signatar som har signert eller avvist, gir 409. delivery: "email" flytter en signatar fra innebygd signering til e-post (se under).

curl -X PATCH -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" \
  -d '{"email":"kari.nordmann@kunde.no"}' "$RS/envelopes/$ID/signers/$SIGNER"

Arkivere: POST /envelopes/{id}/archive og /restore

Arkivering flytter signeringen ut av lista, men sletter ingenting; hent den med archived=only eller archived=all. En signering som venter på signaturer, må avbrytes først (422). /restore legger den tilbake.

Kommentarer: GET /envelopes/{id}/comments

Kommentarene på signeringen, eldste først, fra alle versjoner. page, x og y sier hvor i dokumentet en kommentar er festet (x og y som andel av siden), og parentId hvilken kommentar den svarer på. En kommentar som markerer tekst i dokumentet, har også quote (teksten som ble markert) og highlight (de markerte linjene som [x, y, bredde, høyde], andeler av siden); nålen (x, y) står da i margen ved siden av utdraget. Virker også med en nøkkel som bare kan lese.

{ "comments": [{ "id": "…", "version": 1, "parentId": null, "authorKind": "signer",
  "authorName": "Kari Nordmann", "body": "Feil beløp i punkt 3", "page": 2, "x": 0.41, "y": 0.63,
  "createdAt": "2026-10-20T09:12:00Z" }] }

Dokumenter

Kall Svar
GET /envelopes/{id}/document originalen (PDF)
GET /envelopes/{id}/signed forseglet PDF med signaturside, original og evidence.json som vedlegg; bare completed, ellers 409
GET /envelopes/{id}/evidence evidence.json slik den ligger i den forseglede PDF-en; bare completed
GET /envelopes/{id}/evidence.zip bevispakken: signert.pdf, originalen av hver versjon (originaler/versjon-N.pdf), audit.pdf, evidence.json og README.txt om hvordan dokumentet kontrolleres; bare completed, ellers 409
curl -H "Authorization: Bearer $RS_KEY" -o signert.pdf "$RS/envelopes/$ID/signed"
curl -H "Authorization: Bearer $RS_KEY" "$RS/envelopes/$ID/evidence"
curl -H "Authorization: Bearer $RS_KEY" -o bevispakke.zip "$RS/envelopes/$ID/evidence.zip"

evidence.json i bevispakken har format: "relation-sign/evidence-package/v1" og lages når pakken hentes: hendelseskjeden med prevHash og hash for hver hendelse (oppskriften står i chain.algorithm), signatarene og hvordan de signerte, seglet, SHA-256 for alle dokumentversjoner og for hver fil i pakken. Fødselsdato, rå identitetsdata fra BankID og engangskoder er aldri med.

evidence.json har format: "relation-sign/evidence/v1", signatarene med identitet og tidspunkt, hele hendelseskjeden med hasher, versjoner og kommentarer. Fødselsnummer er aldri med.

Innebygd signering

For et hvilket som helst system som vil ha signering i sin egen flyt, for eksempel regnskap, kontrakter, eiendomsmegling eller CRM: brukeren trykker «Signer» i programmet, signerer i Relation Sign med BankID eller kode, og kommer rett tilbake til programmet.

Brukeren trykker «Signer»  →  POST /envelopes  { send: true, signers: [{ delivery: "none", returnUrl }] }
                           ←  201  { signers: [{ signingUrl }] }
Programmet sender brukeren til signingUrl  →  BankID  →  signert
Relation Sign sender brukeren til  returnUrl?rs_envelope=…&rs_signer=…&rs_status=signed
Webhook signer.signed, så envelope.completed  →  programmet henter /signed

Felt på signataren

Felt
delivery email (standard) eller none none: vi sender ingen invitasjon, påminnelse eller annen e-post om signeringen. Engangskoder (otp_email, otp_sms, lesetilgang med kode) sendes fortsatt: de er identitetsbekreftelsen. Ikke for method: drawn
returnUrl streng, maks 2000 hvor signeringssiden sender signataren etter å ha signert, avvist eller trykket «Tilbake». Må ligge på en av integrasjonens tillatte adresser (se under), ellers 422 med code: "return_url_not_allowed". Virker også med delivery: "email"
receipt bool, standard true bare delivery: "none": om signataren får kvitteringen med det signerte dokumentet på e-post når alle har signert
appName streng, maks 60 navnet signataren ser på vei tilbake («Fortsett i …»). Bare når returnUrl ligger på en av Relation Labs sine egne adresser (se under); ellers brukes navnet på API-nøkkelen, og feltet gir 422

Signeringen vises fortsatt i Relation Sign. Avsenderen ser «Signerer i Eksempel Regnskap» på signataren, og kan trykke «Send på e-post i stedet». Feltene kan bare settes fra API-et.

Lenken: signingUrl

Svaret fra POST /envelopes med send: true og fra POST /envelopes/{id}/send har signingUrl på hver signatar med delivery: "none" som har tur. Det er hele lenken; send brukeren dit, i samme fane eller en ny. Hver utlevering står i hendelsesloggen (link_issued). GET, lister og webhooks viser aldri lenken.

Med signingOrder: "sequential" har senere signatarer ikke tur ennå. Når turen kommer, sender vi webhooken signer.ready; hent da lenken med POST /envelopes/{id}/signers/{signerId}/link. Det kallet tar også en valgfri { "returnUrl": "…" } som erstatter den lagrede, så du kan sende brukeren tilbake til akkurat den siden hen kom fra.

Tilbake til programmet

Etter signeringen viser siden seglet og sender brukeren videre etter tre sekunder, med knappen «Fortsett i Eksempel Regnskap» for den som ikke vil vente. Vi venter ikke på forseglingen. Ved avvisning får brukeren knappen. Lenken «Tilbake til Eksempel Regnskap» øverst på siden lar brukeren gå tilbake uten å signere.

https://app.eksempel.no/dokumenter/123?rs_envelope=<id>&rs_signer=<id>&rs_status=signed
rs_status
signed brukeren signerte
declined brukeren avviste
aborted brukeren gikk tilbake uten å signere; ingenting er endret

Hvem som helst kan skrive en slik adresse. Stol derfor på webhooken eller GET /envelopes/{id}, aldri på rs_status alene.

Tillatte adresser

En returnUrl må ligge på en adresse integrasjonen har fått godkjent, så sign.relationlabs.no aldri kan brukes til å videresende noen til en falsk side etter en ekte BankID-innlogging.

  • API-nøkkel: en administrator legger inn adressene under Integrasjoner → API-nøkkelen → Signering i eget system, sammen med appnavnet brukeren ser på knappen.
  • Tilkobling fra katalogen (OAuth): klientens redirectUris gir de tillatte adressene, og appnavnet er katalognavnet. Kunden trenger ikke gjøre noe.
  • Relation Labs sine egne adresser, som kundeportalen i Relation OS, er tillatt for alle nøkler og tilkoblinger (TRUSTED_RETURN_ORIGINS på serveren). Der kan hver signatar også få sitt eget appName.

En tillatt adresse er en opprinnelse, som https://app.eksempel.no, med eventuell port. https://*.eksempel.no dekker alle underdomener (ikke eksempel.no selv). returnUrl må være en hel https-adresse på nøyaktig samme opprinnelse. http://localhost og http://127.0.0.1 er tillatt for lokal utvikling.

Når brukeren aldri signerer i programmet

PATCH /envelopes/{id}/signers/{signerId} med { "delivery": "email" } gir signataren invitasjonen på e-post med en gang (hvis hen har tur), og påminnelsene som vanlig fra da av. Motsatt vei går ikke (422).

Lenke til «Ny signering»

Uten API og uten nøkkel: en lenke eller knapp i et hvilket som helst system som åpner «Ny signering» ferdig utfylt. Den som klikker, må være logget inn i Relation Sign (ellers logger hen inn først og kommer tilbake til lenken), velger PDF-en og sender som vanlig. Alt i lenken er forslag som kan endres i skjemaet.

https://sign.relationlabs.no/ny?tittel=Avtale+1042&ref=ORD-1042&frist=14
  &navn=Kari+Kunde&epost=kari@kunde.no&mobil=
  &navn=Ola+Nordmann&epost=ola@kunde.no&mobil=%2B4791234567
Parameter Hva
tittel Tittelen på signeringen (høyst 200 tegn)
melding Meldingen til signatarene (høyst 2000 tegn)
navn, epost, mobil Én signatar per gang de gjentas, i samme rekkefølge. mobil kan være tom. Høyst 20
frist Fristen i dager, 1–180 (ellers organisasjonens vanlige)
ref Systemets egen referanse (høyst 200 tegn). Lagres som externalRef, kommer tilbake i webhookene og kan brukes i GET /envelopes?externalRef=

Lenken lagrer seg som det påbegynte skjemaet med en gang, så en omlasting finner det igjen. En lenke kan settes sammen under «Integrasjoner» → «Katalog» → «Lenke fra eget system».

Mapper

Mapper ordner signeringene per kunde, prosjekt eller noe annet. De hører til organisasjonen, kan ligge inntil tre nivåer dypt, og et navn er unikt blant mappene på samme sted (uansett store og små bokstaver). En signering ligger i én mappe eller ingen. externalRef er deres egen id for mappen, for eksempel et prosjekt i Relation OS, og er unik i organisasjonen.

Liste: GET /folders?archived=

curl -H "Authorization: Bearer $RS_KEY" "$RS/folders"

Svar:

{
  "folders": [{
    "id": "5d0e…", "parentId": null, "name": "P42 Gressvik", "color": null, "kind": "project",
    "externalRef": "relation-os:stalbygg:project:42", "createdAt": "…", "archivedAt": null,
    "depth": 1, "path": ["P42 Gressvik"], "count": 3, "total": 5
  }],
  "all": 12, "unfiled": 4, "inArchived": 0, "maxDepth": 3
}

Mappene kommer dybde først, sortert på navn. count er signeringene rett i mappen og total med mappene under; arkiverte signeringer telles ikke. Arkiverte mapper er bare med når archived=true.

Opprette: POST /folders

Felt Type
name streng, påkrevd maks 80 tegn
parentId uuid mappen den skal ligge i; maks tre nivåer
externalRef streng, maks 200 deres id for mappen
color slate, blue, teal, green, amber, orange, red eller violet valgfri
kind customer eller project valgfri

Svar 201 med mappen. Finnes det allerede en mappe med samme externalRef, svarer kallet 200 med den, så det er trygt å prøve igjen. Et navn som er tatt på samme sted gir 409.

Mappe per prosjekt fra Relation OS

Send folder når signeringen opprettes:

{ "title": "Endringsmelding EM-12", "folder": { "externalRef": "relation-os:stalbygg:project:42", "name": "P42 Gressvik" }, "signers": [ … ] }

Første gang lages mappen øverst med name (og kind: "project"); senere kall med samme externalRef bruker den samme mappen, også om name er endret. En mappe som er arkivert, hentes tilbake. Finnes det allerede en mappe øverst med samme navn og uten externalRef, tas den i bruk. Er navnet tatt av en annen mappe, får den nye mappen externalRef i parentes bak navnet.

Å flytte signeringer mellom mapper, gi nytt navn, arkivere og slette gjøres i Relation Sign. En arkivert mappe er skjult, men signeringene i den beholder folderId; bare en tom mappe kan slettes.

Dokumentmaler

Malene i «Dokumentmaler» kan fylles ut med API-et, og en integrasjon eller en AI-agent kan skrive egne maler i Markdown. Serveren er fasit: den har de samme reglene som veiviseren i appen (påkrevd, påkrevd når en del vises, skjult, summer, partsfelt, enheter, utregnede kolonner), og sier hva som mangler med etikett og kode, så en agent kan stille oppfølgingsspørsmålene uten egne regler.

  • En mal i en annen organisasjon gir 404. Alle i organisasjonen ser og fyller ut organisasjonens maler; den som laget en mal, og en administrator, kan endre, publisere og arkivere den (403 for andre, også med en personlig nøkkel).
  • En lesenøkkel kan lese, sjekke svar (check), forhåndsvise (preview) og sjekke en mal (validate), men ikke lage, lagre, fylle ut, publisere eller arkivere (403 read_only_key). Det samme gjelder en tilkobling med bare envelopes:read.
  • Utfylling (fill) krever det samme som POST /envelopes (avtalen), og lager bare et utkast. Det sendes med POST /envelopes/{id}/send, som før.
  • «Dette er meg» (me: true på en part) er eieren av en personlig nøkkel. Med en nøkkel fra Integrasjoner er det avsenderen: senderEmail, ellers nøkkelens reserveavsender, som på POST /envelopes. En personlig nøkkel med en annen senderEmail gir 422 personal_key.
  • Grenser per nøkkel: utfylling 20 i minuttet, ny mal og lagring 60, publisering 30, sjekk og validate 120, og 120 forhåndsvisninger i minuttet som ikke ligger i bufferen (429 med retryAfter).

Hvilken mal: ref

ref Er
standard:samboer en standardmal (slug)
7c1e… en egen mal, versjonen som gjelder
7c1e…@3 versjon 3 av en egen mal
7c1e…@draft utkastet til en egen mal: kan leses, sjekkes og forhåndsvises, men ikke fylles ut

Liste: GET /document-templates?q=

Organisasjonens publiserte egne maler (etter navn), så standardmalene for kontotypen i samme rekkefølge som i appen (en bedrift får kategoriene Avtaler, Arbeid og oppdrag og Selskap først, med den mest brukte malen først i hver). q søker som biblioteket i appen: hvert ord i q må stå i navnet eller beskrivelsen til en egen mal, eller i navnet, sammendraget, loven, kategorien eller søkeordene (keywords) til en standardmal, uansett store og små bokstaver. Småord som «av», «og» og «for», og ord rundt et malsøk som «mal», «signering» og «pdf», telles ikke med når q har andre ord, så både q=mc og q=salg av bil finner «Salg av kjøretøy». Standardmalene som treffer best, kommer først: et ord som er et helt ord i navnet eller et søkeord, teller mer enn starten av et ord, som teller mer enn et treff inni et ord, og alle foran dem som har ordene bare i sammendraget, loven eller kategorien.

{ "templates": [
  { "ref": "7c1e…", "kind": "own", "name": "Leie av parkeringsplass", "summary": "…", "version": "2", "pinnedRef": "7c1e…@2" },
  { "ref": "standard:samboer", "kind": "standard", "name": "Samboeravtale", "summary": "…",
    "category": "samliv", "categoryLabel": "Samliv", "audience": "private",
    "keywords": ["samboer", "samboerkontrakt", "…"], "version": "2026-11-03.3", "pinnedRef": "standard:samboer" }
] }

Spørsmålene: GET /document-templates/{ref}

Partene (roles), spørsmålene i veiviserens rekkefølge (questions, gruppe for gruppe), summene (sums), titlePattern og «Før du begynner» (warnings) for en standardmal. Hvert spørsmål sier når det spørres (shownWhen) og når det må besvares (requiredWhen), i ord og som vilkår (anyOf: ett av dem holder), og hvordan svaret skrives (answer). null betyr alltid (spørres) og aldri (ut over required).

{
  "ref": "standard:samboer", "kind": "standard", "name": "Samboeravtale", "version": "2026-11-03.3",
  "warnings": ["Samboere arver ikke hverandre etter loven, …"],
  "roles": [{ "key": "samboer", "label": "Samboer", "signs": true, "min": 2, "max": 2,
              "fields": ["name", "email", "phone", "address", "birthDate"], "required": ["name", "email"] }],
  "questions": [
    { "key": "bolig", "label": "Boligen", "type": "choice", "group": "Boligen", "required": true,
      "requiredWhen": null, "shownWhen": null, "answer": "ett av alternativene i options, skrevet nøyaktig likt",
      "options": ["Vi eier boligen sammen", "Den ene av oss eier boligen", "Vi leier boligen"] },
    { "key": "bolig_eier", "label": "Hvem eier boligen", "type": "party", "group": "Boligen", "required": false,
      "requiredWhen": { "text": "når «Boligen» er «Den ene av oss eier boligen»",
                        "anyOf": [{ "key": "bolig", "is": "Den ene av oss eier boligen" }] },
      "shownWhen":    { "text": "når «Boligen» er «Den ene av oss eier boligen»",
                        "anyOf": [{ "key": "bolig", "is": "Den ene av oss eier boligen" }] },
      "answer": "en av partene, {\"role\": \"<rolle>\", \"index\": 0} …", "parties": { "roles": ["samboer"], "others": [] } }
  ],
  "sums": [{ "keys": ["andel_1", "andel_2"], "equals": 100, "text": "«Samboer 1 sin eierbrøk» og «Samboer 2 sin eierbrøk» skal bli 100 til sammen" }],
  "titlePattern": ""
}

Et vilkår er { "key", "is" } (et alternativ, eller true for ja), { "key", "isNot" } (ikke dette alternativet, eller ikke ja, også ubesvart) eller { "key", "filled": true|false }. min og max står i svarets form: øre for et beløp, ÅÅÅÅ-MM-DD for en dato.

En rolle har help når malen sier noe om parten. En rolle med "min": 0 er en part som kan utelates, også en som signerer: den trengs når en del som vises, skriver den (neededWhen), og står den bare i valgfrie deler, spørres den bare når en av dem vises (shownWhen, med samme vilkår). Ellers legger du den til eller ikke. Er den ikke med, sender du ingen parter for den (eller en tom liste); den blir verken signatar eller kort, og parter sendt for en rolle som ikke spørres, fjernes. I gavebrevet er det slik for Mottaker og Verge:

{ "key": "verge", "label": "Verge", "help": "Vergen eller vergene tar imot gaven og signerer for barnet, …",
  "signs": true, "min": 0, "max": 2, "fields": ["name", "email", "phone", "address"], "required": ["name", "email"],
  "neededWhen": { "text": "når «Mottaker er under 18 år» er ja", "anyOf": [{ "key": "mindrearig", "is": true }] },
  "shownWhen":  { "text": "når «Mottaker er under 18 år» er ja", "anyOf": [{ "key": "mindrearig", "is": true }] } }

Spørsmålene som avgjør om en slik part er med (mindrearig her), står først i questions, med group «Partene», slik veiviseren stiller dem rett over partens kort. Et partsfelt kan bare peke på en part som er med: peker det på en part som fjernes, gir utfyllingen 422 party_unknown.

Svarene sendes som values: { fields, parties }:

Type Svaret i fields
text, longtext, address tekst (høyst 500, 5000 og 300 tegn)
number, percent tall (prosent 0–100, høyst to desimaler)
money øre som heltall: 1250000 er kr 12 500,00
date "2026-11-03"
choice ett av options, nøyaktig likt
boolean true eller false
orgnr, regnr "923609016", "AB 12345"
party { "role": "samboer", "index": 1 } (fra 0) eller { "other": "Begge" }
rows [{ "kolonne": verdi, … }]; utregnede kolonner sendes ikke

parties er partene per rolle i rekkefølge: { "samboer": [{ "me": true }, { "name": "Martine Berg", "email": "martine@example.no" }] }. Hver part i en rolle som signerer, trenger e-post (invitasjonen går dit); BankID blir metoden.

pinnedRef er akkurat versjonen spørsmålene gjelder (<id>@3; for en standardmal det samme som ref). Fyll ut den, så kommer ikke en ny versjon imellom. Et utkast (<id>@draft) har ingen pinnedRef: det endres ved hver lagring, og det fylles aldri ut.

Med ?format=markdown kommer malen som Markdown i stedet (text/markdown), en standardmal slik en egen mal ville hatt den, med eksempelet. Med ?format=markdown-json kommer det samme som JSON: { ref, markdown, notes }, der notes er det Markdown ikke kan si (code: not_in_markdown, med path). (format=markdown med Accept: application/json gir også JSON.) Det er utgangspunktet for «lag en mal basert på samboeravtalen, men …»: endre teksten og send den til POST /document-templates. Se Egne maler i Markdown.

Sjekke svarene: POST /document-templates/{ref}/check

{ values, senderEmail? } → hva en utfylling med disse svarene ville avvist, uten PDF:

{
  "ok": false,
  "missing": [
    { "key": "samboer.1.email", "label": "Samboer 2: e-post", "help": "Invitasjonen til å signere sendes hit.", "code": "signer_email" },
    { "key": "bolig_eier", "label": "Hvem eier boligen", "code": "required", "why": "når «Boligen» er «Den ene av oss eier boligen»" },
    { "key": "utgifter", "label": "Hvordan deler dere de felles utgiftene?", "code": "required" }
  ],
  "fieldErrors": {},
  "hidden": ["kjopesum", "egenkapital_1", "…"]
}

missing står i veiviserens rekkefølge (partene først), med code required, signer_email, too_few_parties (roles.<rolle>, med params.min, og why for en part som kan utelates og som en del som vises, trenger) eller no_signer. fieldErrors er svar som er feil (samme koder som en 422 fra fill, se fieldErrors under). hidden er spørsmålene svarene skjuler: de skal ikke spørres, og svarene på dem fjernes. roles.<rolle> i hidden er en part som kan utelates og ikke skal spørres; partene for den fjernes. ok er true når fill går gjennom.

Forhåndsvise: POST /document-templates/{ref}/preview

{ values, sample?, letterhead? } → PDF-en med svarene så langt; det som mangler står som «[Etikett]», og sample: true fyller inn malens eksempel der svar mangler. letterhead: false tar organisasjonens brevhode av en standardmal (se Brevhodet).

Fylle ut: POST /document-templates/{ref}/fill

{ values, title?, envelopeId?, senderEmail?, letterhead?, …innstillinger } → et utkast til signering med PDF-en og partene som signerer som signatarer, svart som GET /envelopes/{id} (201). Uten title gir malens titlePattern navnet. Med envelopeId fylles et utkast fra samme mal på nytt («Endre svarene», 200, samme id): bare ens eget utkast, ellers 409 (draft_not_own, draft_other_template, not_from_template), og 404 for et man ikke ser; uten letterhead beholder utkastet brevhodevalget det hadde. Svar som ikke går gjennom gir 422 validation_failed med fields og fieldErrors ({ "utgifter": { "code": "required", "message": "må fylles ut" } }). Idempotency-Key virker som på POST /envelopes. Utkastet sendes med POST /envelopes/{id}/send.

Utkastets innstillinger kan gis med det samme, med navnene fra POST /envelopes: message, expiresInDays, signingOrder, reminders, confidential, viewerEmails og folderId (null: ingen mappe). De sjekkes sammen med utkastet: en innstilling som ikke går, gir 422 (en mappe nøkkelen ikke ser 404), og da lages ikke noe utkast. Fylles et utkast ut på nytt (envelopeId), endres bare innstillingene som er med. Etterpå endres de med PATCH /envelopes/{id}.

Brevhodet: letterhead

En bedrift kan ha ett brevhode for dokumentmaler (Organisasjon › «Merkevare», «Logo eller banner på standardmalene»): logoen sin, eller et banner, øverst på første side av standardmalene, mens «Laget med Relation Sign» står nederst som før. Når det er slått på for standardmaler, får en standardmal det fra preview og fill uten at noe sendes. letterhead: false gir ett dokument uten, som bryteren «Med logoen til …» i veiviseren, og valget lagres med signeringen. Fylles et utkast ut på nytt (envelopeId) uten letterhead, beholdes valget det hadde. En egen mal har sitt eget utseende (letterhead gjelder ikke den); bruker den organisasjonens logo, får den også brevhodets banner og plassering når den ikke har egne. Et personlig arbeidsområde har ikke brevhode. Bare en administrator endrer brevhodet, i appen.

Merkevaren: GET /brand og PUT /brand

Organisasjonens «Merkevare» (Organisasjon › Merkevare i appen): farger (#rrggbb), fonter, topptekst og bunntekst i tre deler, størrelser, vannmerke, forside og firmaopplysningene brikkene skriver. Egne maler bruker den, og standardmalene tar farger, fonter og logostørrelse når standards er på. GET /brand svarer med merkevaren, fontene som følger med (families), organisasjonens egne fonter (fonts) og brikkene (chips).

PUT /brand legger det som sendes, oppå det som er lagret: et felt som ikke er med, blir stående, og null fjerner en gruppe. Tekstfargen må ha kontrast minst 4,5:1 mot hvitt og hovedfargen minst 3:1 (422 brand_contrast), og en font som verken følger med eller er organisasjonens egen, er 404. Det krever en nøkkel med full tilgang (403 read_only_key ellers), og en personlig nøkkel må kunne administrere organisasjonen (403 admin_key_required); en tilkobling kan ikke endre merkevaren (403 key_required). Egne fonter lastes opp i appen, der den som laster opp, bekrefter retten til å bygge dem inn.

curl -X PUT "$RS/brand" -H "Authorization: Bearer $RS_KEY" -H "Content-Type: application/json" \
  -d '{"colors": {"primary": "#1f4d3a", "accent": "#c8a24a"}, "fonts": {"body": "Charis SIL", "heading": "Vollkorn"},
       "header": {"left": "{firma}", "right": "Org.nr. {orgnr}"}, "footer": {"left": "{tittel}", "right": "{side}"},
       "watermark": "KONFIDENSIELT", "cover": true}'

En egen mal kan ha sin egen utgave av hver gruppe i appearance.brand, også i Markdown-hodet:

appearance:
  brand:
    colors: { primary: "#1d2b53", accent: "#ff5a1f" }
    fonts: { body: Lato, heading: League Spartan }
    footer: { left: "{firma}", right: "{side}" }
    watermark: ""

En gruppe som ikke er med, er merkevarens; watermark: "" er uten vannmerke.

Eksempel: samboeravtale til to personer

En agent med Hauks personlige nøkkel får «send en samboeravtale til Hauk og Martine»:

# 1. Finne malen
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates?q=samboer"
# → { "templates": [{ "ref": "standard:samboer", … }] }

# 2. Spørsmålene (og «Før du begynner», som agenten sier fra om)
curl -H "Authorization: Bearer $RS_KEY" "$RS/document-templates/standard:samboer"

# 3. Sjekke det agenten vet så langt; missing er oppfølgingsspørsmålene
curl -X POST "$RS/document-templates/standard:samboer/check" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"values": {"fields": {"samboer_fra": "2024-08-01", "bolig": "Vi leier boligen",
       "bolig_adresse": "Bjerkeveien 12, 0480 Oslo"},
       "parties": {"samboer": [{"me": true}, {"name": "Martine Berg"}]}}}'
# → missing: samboer.1.email, leiekontrakt («når «Boligen» er «Vi leier boligen»»), utgifter

# 4. Når check sier ok: fylle ut til et utkast, med melding og frist
curl -X POST "$RS/document-templates/standard:samboer/fill" -H "Authorization: Bearer $RS_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: samboer-hauk-martine" \
  -d '{"values": {"fields": {"samboer_fra": "2024-08-01", "bolig": "Vi leier boligen",
       "bolig_adresse": "Bjerkeveien 12, 0480 Oslo", "leiekontrakt": {"other": "oss begge"},
       "utgifter": "Vi deler likt"},
       "parties": {"samboer": [{"me": true}, {"name": "Martine Berg", "email": "martine@example.no"}]}},
       "title": "Samboeravtale Hauk og Martine", "message": "Her er avtalen vi snakket om.", "expiresInDays": 14}'
# → 201 { "id": "1b7c…", "status": "draft", "signers": [{ "name": "Hauk Olaussen", … }, { "name": "Martine Berg", … }] }

# 5. Sende, etter at personen har sagt ja
curl -X POST "$RS/envelopes/1b7c…/send" -H "Authorization: Bearer $RS_KEY"

Egne maler i Markdown

En egen mal skrives i samme Markdown som standardmalene: et YAML-hode mellom to linjer med ---, og så teksten.

---
name: Leie av parkeringsplass
summary: Utleie av én plass i garasjeanlegget.
titlePattern: Parkeringsplass {{plass}}
roles:
  - {key: utleier, label: Utleier, signs: true, fields: [email]}
  - {key: leier, label: Leier, signs: true, fields: [email, phone]}
variables:
  - {key: plass, label: Plassnummer, type: text, required: true}
  - {key: leie, label: Leie per måned, type: money, required: true, min: 1}
  - {key: lading, label: Med lading, type: boolean}
---
# Leie av parkeringsplass

::: parter utleier

::: parter leier

§ Plassen
Leier får bruke plass {{plass}} for {{leie}} i måneden.

::: hvis lading
Plassen har lader. Strømmen betales etter måler.
:::

::: signatur

Hodet har name (påkrevd, høyst 120 tegn), summary (beskrivelsen), titlePattern, appearance (useOrgLogo, logoAlign: left, center eller right, header: first eller every, og logoAssetId og bannerAssetId for bilder organisasjonen har lastet opp), roles, variables, sums og example, med feltene fra innholdet (key, label, type, required, help, group, options, default, min, max, unit, columns, maxRows, vat, roles, others; for en rolle help, signs, pays, min, max og fields). min: 0 er en part som kan utelates, også en som signerer: legg partslisten og brikkene i den ::: hvis-delen som handler om parten, så er den med nøyaktig når delen vises. Minst én rolle som signerer, må ha min 1 eller mer. pays: true går bare på en rolle som signerer, og betyr at partene er forbrukere som betaler: knappen deres sier «Signer med plikt til å betale», den signerte PDF-en legges ved deres egen e-post (se Signatar som betaler), og signatarene har "pays": true. Nøklene som bare standardmalene har (slug, version, category, audience, legalBasis, reviewedBy, warnings, keywords, rank), leses forbi med en merknad, så en standardmal fra ?format=markdown eller fra fila kan brukes som den er. En ny mal i en bedrift får organisasjonens logo når hodet ikke nevner et bilde eller useOrgLogo, som i appen; appearance: {useOrgLogo: false} gir en mal uten den (også med content).

Teksten:

Skrives Blir
# , ## , ### overskrift
§ Tittel, §§ Tittel, §§§ Tittel nummerert punkt på nivå 1–3; det varer til neste § på samme eller høyere nivå, til slutten av delen (::: hvis) det står i, eller til ::: slutt §
§ alene et punkt uten tittel (nummeret står foran første avsnitt)
::: slutt §, ::: slutt §§, ::: slutt §§§ punktet på det nivået, og punktene inni det, slutter her; det som følger, står på nivået over (etter alle punktene med ::: slutt §)
{{pris}}, {{selger.name}}, {{linjer.total}}, {{linjer.sum.antall}} svaret, et partsfelt (rolle med høyst én part), tall fra en tabell
::: hvis nøkkel … ::: vises når ja-/nei-spørsmålet er ja, eller feltet er fylt ut
::: hvis ikke nøkkel … ::: vises når det ikke er ja, eller ikke fylt ut
::: hvis nøkkel = verdi / ::: hvis nøkkel != verdi … ::: vises når valget er (ikke er) verdien
::: parter rolle partene i rollen
::: rader nøkkel tabellen av en rows-variabel
::: signatur, ::: sideskift, --- signaturfeltet, sideskift, strek
**fet**, *kursiv*, [tekst](https://…), - punkt, 1. punkt, | tabell | som i Markdown (tabeller med overskriftsrad)
- punkt og under det - underpunkt (eller 1. underpunkt) en liste inni et listepunkt: et punkt med innrykk under et annet hører til det, i så mange nivåer som trengs

En linje som starter med § , er alltid et punkt, og en del (::: hvis) kan ikke ligge inni en annen. En del som starter med et punkt på samme nivå som punktet før den (§ Leie … ::: hvis moblert / § Møbler / :::), står ved siden av det punktet og avslutter det, som i editoren; en del uten punkter etter et punkt havner inni punktet, med mindre ::: slutt § står foran den.

§ Leieforholdet
Leien er {{leie}} i måneden.

::: hvis moblert
§ Møbler
Møblene på listen følger med.
:::

§ Depositum
Tre måneders leie.

::: slutt §

::: parter leier
  • POST /document-templates/validate { markdown } → { ok, problems, questions }, og lagrer ingenting. Hvert problem har line (den første --- er linje 1) når det kan sies, path, code, message og severity: error (kan ikke lagres: Markdown-en kan ikke leses, en ukjent type, en nøkkel som spør etter fødselsnummer), not_ready (lagres som utkast, men kan ikke publiseres: en brikke til en variabel som ikke finnes, ingen part som signerer, et tomt dokument) eller note (stopper ingenting). For feil i YAML-syntaksen peker linjen på der listen eller objektet feilen står i, starter.
  • POST /document-templates { markdown } (eller { content, name, summary } som editoren lagrer det) → 201 med malen som utkast, ok, problems og questions. error gir 422 template_invalid med problems, og ingenting lagres. Et navn som er tatt gir 409. Idempotency-Key gir samme mal tilbake.
  • PUT /document-templates/{id} { markdown } lagrer utkastet (og navn og beskrivelse fra hodet). Hadde utkastet noe Markdown ikke kan si, er det borte, og svaret sier hva som note-problemer med code: lost_on_save. path på dem peker inn i utkastet slik det var før lagringen (som notes fra <id>@draft?format=markdown-json før lagringen), ikke i det nye. Hent dem før du lagrer, og spør personen om det er greit at det forsvinner.
  • content leses strengt: et felt innholdet ikke har, gir 422 template_invalid.
  • POST /document-templates/{id}/publish gjør utkastet til versjonen som fylles ut: 201 { ref: "<id>@2", version, publishedAt, created }, 200 når utkastet er versjonen som gjelder, 422 template_not_ready med problems.
  • DELETE /document-templates/{id} arkiverer malen (204). Det kan ikke angres, men utkastet (<id>@draft, også som Markdown) kan fortsatt hentes av den som kunne endre malen.

Det editoren kan lage som Markdown ikke kan si, er med i malen, men ikke i ?format=markdown: bilder i teksten, understreking, linjeskift inni et avsnitt (skrives som mellomrom), justering, tomme avsnitt, flere avsnitt i et listepunkt, flere avsnitt eller lister i en celle, en tabell uten overskriftsrad og kolonnebredder. Punkter, deler, det som står etter et punkt (::: slutt §) og lister i lister kommer tilbake der de stod. Hver ting står som en kommentar øverst i hodet, og Relation-Sign-Markdown-Notes sier hvor mange (eller som notes med ?format=markdown-json). Lagres Markdown-en tilbake, er de borte, og PUT sier det (lost_on_save).

Idempotens

Send Idempotency-Key på POST /envelopes, POST /document-templates/{ref}/fill og POST /document-templates når forespørselen kan bli sendt to ganger (tidsavbrudd, nytt forsøk fra en kø):

  • Samme nøkkel og samme forespørsel innen 24 timer gir samme signering (eller samme mal) tilbake, med headeren Idempotent-Replayed: true. Det sendes ingen nye e-poster.
  • «Samme forespørsel» betyr samme payload og samme PDF (SHA-256), uansett om den kom som multipart eller JSON.
  • Samme nøkkel med en annen forespørsel gir 422.
  • Mens den første forespørselen pågår, gir et nytt forsøk 409; prøv igjen.
  • Feiler forespørselen (for eksempel 422), er nøkkelen ikke brukt opp.
  • Nøkler gjelder per API-nøkkel og glemmes etter 24 timer.

Bruk en nøkkel som sier hva som sendes, for eksempel relation-os:stalbygg:change_order:<id>:rev<revisjon>.

Webhooker

En administrator registrerer en mottaker (POST /api/webhooks, se under). Relation Sign sender da en POST til adressen for hver hendelse i organisasjonen.

Levering

POST <din adresse>
Content-Type: application/json
User-Agent: RelationSign-Webhooks/1
Relation-Sign-Event: envelope.completed
Relation-Sign-Delivery: 5d0e…           (samme på alle forsøk)
Relation-Sign-Signature: t=1760870400,v1=3b1f…

{ "id": "…", "type": "envelope.completed", "createdAt": "…", "data": { "envelope": { … }, "signer": { … }, "comment": { … } } }
  • Bare organisasjoner med API i planen får webhooker. Mister planen API-et, legges ingenting nytt i køen, og leveringer som venter, settes til failed med feilen «planen til organisasjonen har ikke lenger API og webhooks».
  • Svar med 2xx innen 10 sekunder. Alt annet, også videresending (3xx), er en feil.
  • Nye forsøk etter 30 s, 1, 2, 4, 8 ... minutter (maks 6 timer mellom), totalt 10 forsøk. Deretter failed i leveringsloggen. Hver ventetid spres tilfeldig med inntil 20 % begge veier.
  • Svarer dere 429 eller 503 med Retry-After (sekunder eller dato), venter vi så lenge, men aldri over 6 timer.
  • 410 Gone og 413 gir ingen nye forsøk: leveringen blir failed med en gang.
  • Kroppen er den samme på alle forsøk; t i signaturen er tidspunktet for forsøket.
  • Mottakeren får 10 sekunder (oppkobling, TLS og svar). Vi leser bare den første 1 KB av svaret, og den vises i leveringsloggen.
  • Rekkefølgen er ikke garantert. Bruk data.envelope.status og tidspunktene, og dedupliser på id.
  • Adressen må være https og kan ikke peke på interne adresser (private nett, loopback, link-local, metadata). Det sjekkes på nytt ved hver levering: alle A- og AAAA-adressene navnet peker på må være offentlige (én intern er nok til å avvise), vi kobler til nettopp den adressen vi sjekket, og videresendinger følges aldri.
  • Leveringsloggen viser status, HTTP-kode, varighet, antall forsøk, neste forsøk, hele kroppen som ble sendt og starten av svaret. Leveringer slettes etter 90 dager, siden de inneholder navn og e-postadresser.

Pause, «Send på nytt» og automatisk avslåing

  • Pause: en webhook på pause får ingenting. Hendelser som skjer mens den er på pause, og leveringer som ventet på et nytt forsøk da den ble satt på pause, står som skipped («Hoppet over») i leveringsloggen. De sendes ikke når webhooken slås på igjen; bare hendelser etter det sendes. Testknappen virker også på pause, så dere kan sjekke mottakeren først.
  • Send på nytt: hvilken som helst levering (feilet, levert eller hoppet over) kan sendes på nytt. Det blir en ny levering med ny Relation-Sign-Delivery, men samme hendelse: samme kropp og samme id, så mottakeren kan deduplisere. Den prøves med en gang og deretter som vanlig. Webhooken må være på (ellers 409).
  • Automatisk avslåing: når de siste 15 forsøkene på rad mot en webhook har feilet, og den første av dem er minst tre døgn gammel, slår Relation Sign av webhooken og sender en e-post til alle administratorene i organisasjonen. Integrasjoner viser et banner med siste feil og en knapp for å slå den på igjen. Leveringer som ventet, og hendelser mens den er av, står som skipped og sendes ikke senere. Ett vellykket svar (2xx) nullstiller tellingen.

Bytte hemmelighet

«Bytt hemmelighet» (POST /api/webhooks/{id}/rotate-secret) gir en ny hemmelighet, som vises én gang. I 24 timer etterpå signeres hver melding med begge: headeren har da to v1, først med den nye og så med den gamle:

Relation-Sign-Signature: t=1760870400,v1=<ny>,v1=<gammel>

Mottakeren godtar meldingen hvis én av v1 stemmer med hemmeligheten den har (eksemplene under gjør det). Bytt hemmeligheten hos mottakeren innen 24 timer; etterpå er det bare den nye som signerer. Bytter dere igjen innen 24 timer, slutter den eldste å virke med en gang.

Verifisere signaturen

v1 er heks av HMAC-SHA256 med hemmeligheten (whsec_...) over <t>.<rå kropp>. Sjekk alltid den rå kroppen før du parser den, avvis t som er mer enn fem minutter fra nå, og godta meldingen hvis én av v1 stemmer (det kan være to rett etter at hemmeligheten er byttet).

Svar 401 når signaturen ikke stemmer. Knappen «Sjekk signaturen» under Integrasjoner sender én melding med riktig signatur og én med feil, og sier fra hvis mottakeren godtar begge.

Go:

package relationsign

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// VerifyRequest reads the body and checks Relation-Sign-Signature.
func VerifyRequest(r *http.Request, secret string) ([]byte, error) {
	body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
	if err != nil {
		return nil, err
	}
	var ts string
	var sigs []string
	for _, part := range strings.Split(r.Header.Get("Relation-Sign-Signature"), ",") {
		k, v, _ := strings.Cut(strings.TrimSpace(part), "=")
		switch k {
		case "t":
			ts = v
		case "v1":
			sigs = append(sigs, v)
		}
	}
	sec, err := strconv.ParseInt(ts, 10, 64)
	if err != nil {
		return nil, errors.New("missing timestamp")
	}
	if d := time.Since(time.Unix(sec, 0)); d > 5*time.Minute || d < -5*time.Minute {
		return nil, errors.New("timestamp outside tolerance")
	}
	m := hmac.New(sha256.New, []byte(secret))
	m.Write([]byte(ts + "."))
	m.Write(body)
	want := hex.EncodeToString(m.Sum(nil))
	for _, s := range sigs {
		if hmac.Equal([]byte(s), []byte(want)) {
			return body, nil
		}
	}
	return nil, errors.New("signature does not match")
}

TypeScript (Node):

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

export function verifyRelationSign(rawBody: Buffer, header: string | undefined, secret: string): boolean {
  if (!header) return false;
  let ts = "";
  const sigs: string[] = [];
  for (const part of header.split(",")) {
    const [k, v] = part.trim().split("=", 2);
    if (k === "t") ts = v;
    if (k === "v1") sigs.push(v);
  }
  const sec = Number(ts);
  if (!Number.isInteger(sec) || Math.abs(Date.now() / 1000 - sec) > 300) return false;
  const want = createHmac("sha256", secret).update(`${ts}.`).update(rawBody).digest();
  return sigs.some((s) => {
    const got = Buffer.from(s, "hex");
    return got.length === want.length && timingSafeEqual(got, want);
  });
}

// Express: app.post("/hook", express.raw({ type: "application/json" }), (req, res) => {
//   if (!verifyRelationSign(req.body, req.get("Relation-Sign-Signature"), process.env.RS_WEBHOOK_SECRET!)) return res.sendStatus(401);
//   const event = JSON.parse(req.body.toString("utf8"));
//   res.sendStatus(204);
// });

Python:

import hashlib
import hmac
import time


def verify_relation_sign(raw_body: bytes, header: str | None, secret: str, tolerance: int = 300) -> bool:
    if not header:
        return False
    ts, sigs = "", []
    for part in header.split(","):
        k, _, v = part.strip().partition("=")
        if k == "t":
            ts = v
        elif k == "v1":
            sigs.append(v)
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False
    want = hmac.new(secret.encode(), ts.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(s, want) for s in sigs)


# Flask: body = request.get_data()  (rå bytes, før du parser JSON)
#   if not verify_relation_sign(body, request.headers.get("Relation-Sign-Signature"), os.environ["RS_WEBHOOK_SECRET"]):
#       abort(401)

C#:

using System.Security.Cryptography;
using System.Text;

public static class RelationSign
{
    public static bool Verify(byte[] rawBody, string? header, string secret, int toleranceSeconds = 300)
    {
        if (string.IsNullOrEmpty(header)) return false;
        string? ts = null;
        var sigs = new List<string>();
        foreach (var part in header.Split(','))
        {
            var kv = part.Trim().Split('=', 2);
            if (kv.Length != 2) continue;
            if (kv[0] == "t") ts = kv[1];
            else if (kv[0] == "v1") sigs.Add(kv[1]);
        }
        if (!long.TryParse(ts, out var sec)) return false;
        if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - sec) > toleranceSeconds) return false;
        using var mac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
        var want = mac.ComputeHash(Encoding.UTF8.GetBytes(ts + ".").Concat(rawBody).ToArray());
        foreach (var s in sigs)
        {
            byte[] got;
            try { got = Convert.FromHexString(s); } catch (FormatException) { continue; }
            if (CryptographicOperations.FixedTimeEquals(got, want)) return true;
        }
        return false;
    }
}

// ASP.NET Core: les Request.Body til byte[] (EnableBuffering) før du parser JSON.

Hendelser

Type Når data
envelope.sent signeringen er sendt envelope
signer.ready det er turen til en signatar med delivery: "none" (med en gang ved parallell signering, når forrige har signert ved fast rekkefølge); hent lenken med /link envelope, signer
signer.viewed en signatar åpnet lenken første gang envelope, signer
signer.signed en signatar signerte envelope, signer
signer.declined en signatar avviste (se signer.declineReason) envelope, signer
envelope.completed alle har signert og PDF-en er forseglet; hent den med /signed envelope (med sealedSha256)
envelope.declined signeringen er avvist (kommer sammen med signer.declined) envelope, signer
envelope.expired fristen gikk ut envelope
envelope.cancelled avsenderen trakk den tilbake envelope
envelope.withdrawn en signatar trakk signaturen sin; signeringen er stoppet envelope, signer (med withdrawReason)
comment.added ny kommentar på dokumentet envelope, signer (hvis en signatar skrev), comment
comment.withdrawn den som skrev en kommentartråd, fjernet den (bare mulig før noen andre har svart eller signert); fjern den hos dere envelope, signer (hvis en signatar fjernet), comment (id, authorName, version)
signature.invalidated en signatur ble nullstilt av en kommentar eller ny versjon envelope, signer (med invalidatedReason)
envelope.version_added avsenderen lastet opp en ny versjon envelope (med ny version og originalSha256)
signer.updated avsenderen endret navn, e-post, telefon, metode eller språk på en signatar som ikke har signert; ny e-post eller telefon gir ny lenke envelope, signer
envelope.extended avsenderen forlenget fristen envelope (med ny expiresAt)
envelope.archived signeringen ble arkivert, av en person eller automatisk; ingenting er slettet envelope (med archivedAt)
envelope.restored signeringen ble hentet fra arkivet envelope
envelope.deleted signeringen ble slettet permanent (av avsenderen, eller automatisk 90 dager etter at den ble avsluttet, når ingen har signert); GET gir 404 etterpå envelope slik den var
envelope.documents_deleted dokumentene ble slettet 5 år etter at signeringen ble avsluttet; signeringen står igjen som verifiseringspost, og nedlasting gir 410 med koden documents_deleted envelope slik den var
ping testknappen { webhookId, message }

data.envelope:

{
  "id": "…", "externalRef": "relation-os:stalbygg:change_order:7f3c", "title": "…",
  "status": "completed", "signingOrder": "parallel", "version": 1,
  "originalSha256": "…", "sealedSha256": "…",
  "createdAt": "…", "sentAt": "…", "completedAt": "…", "expiresAt": "…", "archivedAt": null,
  "folderId": null,
  "sender": { "id": "…", "name": "Per Prosjektleder", "email": "pl@straye.no" },
  "signers": [Signer]
}

Signer: { id, position, name, email, method, status, viewedAt, signedAt, declinedAt, declineReason?, withdrawnAt, withdrawReason?, invalidatedAt, invalidatedReason?, delivery }.

comment: { id, authorKind ("sender" | "signer"), authorName, body, version, page?, x?, y?, quote? }. quote er teksten kommentaren markerer, når den markerer et utdrag.

Tilkoblinger fra katalogen (OAuth 2.0)

Apper i integrasjonskatalogen (Zapier, Make, Tripletex og så videre) kobles til med OAuth 2.0 i stedet for en API-nøkkel. En administrator godkjenner appen for organisasjonen sin, og appen får et tilgangstoken som brukes på /api/v1 akkurat som en nøkkel: Authorization: Bearer rs_oat_.... Bare apper Relation Labs har satt opp (OAUTH_CLIENTS) er klienter. Designet står i docs/specs/2026-10-24-integrasjoner-og-katalog-design.md.

Flyt authorization code med PKCE (S256 er påkrevd)
Autorisasjon https://<domene>/koble/autoriser (samtykkesiden i appen)
Token POST https://<domene>/api/oauth/token (skjemadata, klienthemmelighet med Basic eller client_id/client_secret)
Tilbakekalling POST https://<domene>/api/oauth/revoke (RFC 7009)
Tilganger envelopes:read, envelopes:write, webhooks; tom scope gir alt klienten kan få
  • redirect_uri må være nøyaktig en av klientens. Er den ukjent, sendes brukeren ingen steder. Andre feil sendes tilbake til appen med error og state.
  • Bare en administrator kan godta. En sender ser siden og kan avslå (error=access_denied).
  • Koden kan brukes én gang og varer i 60 sekunder. Brukes den igjen, trekkes tokenene den ga tilbake.
  • Tilgangstokenet varer en time. Refresh token (rs_ort_...) varer 180 dager og byttes ved hver bruk. Kommer et byttet refresh token igjen, er tilgangen fra den godkjenningen trukket tilbake.
  • Flere godkjenninger av samme app i samme organisasjon er én tilkobling med hver sin tokenfamilie. «Koble fra» under Integrasjoner, Tilkoblinger stopper alle med en gang og sletter webhookene tilkoblingen laget.
  • Mangler tokenet tilgangen kallet trenger, svarer API-et 403 med code: "insufficient_scope". Skriving krever envelopes:write, lesing envelopes:read (eller envelopes:write), /webhooks krever webhooks.
  • Tilkoblinger er en del av API-et: de krever API i planen, som API-nøkler. På Løs vekt uten API-tillegget kan ingen godkjenne en tilkobling, og et tilgangstoken får 403. Signeringene betales som ellers.
  • Signeringer en tilkobling lager, har source: { kind: "connection", app, appName }, og revisjonssporet sier «Tilkobling «Zapier»». Andre signeringer har ingen source.
# Bytte koden mot tokens
curl -X POST "https://sign.relationlabs.no/api/oauth/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code -d code="$CODE" \
  -d redirect_uri="$REDIRECT_URI" -d code_verifier="$VERIFIER"
# {"access_token":"rs_oat_...","token_type":"Bearer","expires_in":3600,
#  "refresh_token":"rs_ort_...","scope":"envelopes:read envelopes:write webhooks"}

Hvem er jeg: GET /me

Organisasjonen og tilkoblingen (app og tilganger). Med en personlig nøkkel: nøkkelen og eieren. En API-nøkkel fra Integrasjoner får 404.

Abonnere: POST /webhooks og DELETE /webhooks/{id}

For REST hooks (Zapier, Make): { url, events? } gir 201 { webhook, secret }. Bare med et tilgangstoken; en API-nøkkel får 404 (webhooker for nøkler lages under Integrasjoner). Webhooken hører til tilkoblingen, teller ikke mot organisasjonens ti (høyst 20 per tilkobling), vises ikke under Integrasjoner, Webhooker, og slettes når tilkoblingen kobles fra. Den får hendelser også på Løs vekt, men ikke når organisasjonen ikke lenger er med i piloten. En tilkobling kan bare slette sine egne (404 ellers).

Tilkoblinger er en pilot: bare organisasjoner med funksjonen integrations kan koble til.

Administrasjon (innlogget, rolle admin)

Disse brukes av Relation Sign sitt eget nettgrensesnitt med sesjonscookie, ikke med API-nøkkel. Alt er avgrenset til administratorens organisasjon.

API-nøkler

Metode Sti Kropp Svar
GET /api/api-keys { apiKeys: ApiKey[] }
POST /api/api-keys { name, fallbackUserId?, scope? ("full" | "read"), expiresAt? } 201 { apiKey: ApiKey, key: "rs_live_..." } (nøkkelen vises bare her). Ukjent tilgang eller utløpsdato i fortiden eller mer enn tre år fram gir 422
PATCH /api/api-keys/{id} { fallbackUserId: uuid | null } 200 { apiKey }. Reserveavsender må være en aktiv bruker i organisasjonen (ellers 422); fremmed eller tilbakekalt nøkkel er 404
DELETE /api/api-keys/{id} 204 (tilbakekaller; nøkkelen blir stående i listen)

ApiKey = { id, name, prefix, createdBy: { id, name }, createdAt, lastUsedAt, lastUsedIp, revokedAt, fallbackUser, scope, expiresAt }. Bruk registreres høyst én gang i minuttet per nøkkel, og med en gang når IP-adressen endrer seg.

Personlige nøkler er ikke med her. Hver bruker (alle roller) har sine egne, og en administrator ser alle:

Metode Sti Kropp Svar
GET /api/me/api-keys { apiKeys: ApiKey[] }, egne
POST /api/me/api-keys { name, scope? ("full" | "read" | "admin"), expiresAt? } 201 { apiKey, key }; 403 uten API i planen, og for admin når du ikke er administrator
DELETE /api/me/api-keys/{id} 204 tilbakekaller (?permanent=true sletter en tilbakekalt eller utløpt); en annens nøkkel er 404
GET /api/personal-keys administrator: { apiKeys: ApiKey[] } for alle, createdBy er eieren
DELETE /api/personal-keys/{id} administrator: 204 tilbakekaller

Webhooker

Metode Sti Kropp Svar
GET /api/webhooks { webhooks: Webhook[] }
POST /api/webhooks { url, events? } (tom eller manglende events = alle) 201 { webhook: Webhook, secret: "whsec_..." } (hemmeligheten vises bare her)
PATCH /api/webhooks/{id} { url?, events? } (felt som mangler, beholdes; [] = alle) 200 { webhook }. Hemmeligheten beholdes
DELETE /api/webhooks/{id} 204 (sletter også leveringsloggen)
POST /api/webhooks/{id}/pause 200 { webhook } (se «Pause» over)
POST /api/webhooks/{id}/resume 200 { webhook }. Slår på en webhook som er satt på pause eller slått av automatisk, og nullstiller feiltellingen
POST /api/webhooks/{id}/rotate-secret 200 { webhook, secret: "whsec_..." } (hemmeligheten vises bare her; den gamle signerer i 24 timer til)
GET /api/webhooks/events { events: string[] } (katalogen over)
POST /api/webhooks/{id}/test { delivery: Delivery } (ett forsøk med ping, med en gang; virker også på pause)
POST /api/webhooks/{id}/test-signature { verdict, valid: Delivery, invalid: { statusCode, error, responseBody, durationMs } }. Sender en ping med riktig signatur og en med feil. verdict er ok (riktig godtatt, feil avvist), accepts_invalid, valid_failed eller inconclusive. Bare den riktige havner i leveringsloggen
GET /api/webhooks/{id}/deliveries?status= { deliveries: Delivery[] } (siste 50, uten kroppen; status filtrerer)
GET /api/webhooks/{id}/deliveries/{deliveryId} { delivery: Delivery & { payload, responseBody } }
POST /api/webhooks/{id}/deliveries/{deliveryId}/redeliver { delivery: Delivery } («Send på nytt»; 409 når webhooken ikke er på)

Webhook = { id, url, events, active, state ("active" | "paused" | "disabled" | "off"), pausedAt, disabledAt, disabledReason, consecutiveFailures, failingSince, secretRotatedAt, previousSecretExpiresAt (bare mens den gamle hemmeligheten signerer), createdAt, updatedAt }. off er en webhook Relation OS har skrudd av ved frakobling.

Delivery = { id, eventId, eventType, envelopeId, status ("pending" | "delivered" | "failed" | "skipped"), attempts, maxAttempts, lastStatusCode, lastError, durationMs, nextAttemptAt (bare når pending), deliveredAt, redeliveryOf, createdAt }.

Høyst 10 webhooker per organisasjon.

Varsler i Slack og Teams

Kanaler som får en kort melding med tittel, hvem det gjelder og en lenke til signeringen. Bare for integrasjonspiloten, og uten krav om API i planen. Adressen er en innkommende webhook fra Slack (https://hooks.slack.com/…) eller en arbeidsflyt i Teams (*.logic.azure.com, *.powerplatform.com). Meldingene går i samme kø som webhookene, med de samme nye forsøkene og automatisk avslåing, men er ikke signert. Teams får et Adaptive Card.

Metode Sti Kropp Svar
GET /api/chat-channels { channels: Channel[], events, defaultEvents }
POST /api/chat-channels { kind: "slack" | "teams", label?, url, events? } (tom events = defaultEvents) 201 { channel }
PATCH /api/chat-channels/{id} { label?, events? } (minst én hendelse) 200 { channel }
DELETE /api/chat-channels/{id} 204
POST /api/chat-channels/{id}/test { delivered, error }
POST /api/chat-channels/{id}/resume 200 { channel } (etter automatisk avslåing)

Channel = { id, kind, label, address (vertsnavn og de fire siste tegnene; hele adressen vises aldri igjen), events, state, failingSince, disabledReason, createdAt }. Hendelsene en kanal kan få: envelope.sent, signer.signed, envelope.completed, envelope.declined, envelope.expired og comment.added. Uten valg får den envelope.completed, envelope.declined, envelope.expired og comment.added. Høyst 10 kanaler per organisasjon.

SharePoint (integrasjonspiloten)

Organisasjonens tilkobling, standardmappe og valg per signering (docs/specs/2026-10-25-sharepoint-arkiv-design.md). Innlogget; connect, default og DELETE /api/sharepoint bare for administratorer.

Metode Sti Kropp Svar
GET /api/sharepoint { available, organization: { connected, name, email, default, connectedAt, connectionId }, me: { connected, name, email } }
POST /api/sharepoint/connect { return } { url }: send nettleseren dit (organisasjonen)
POST /api/sharepoint/me/connect { return } { url } (egen konto). Første forsøk er stille (prompt=none)
GET /api/sharepoint/callback 303 tilbake til return med microsoft=koblet eller microsoft-feil=…
PUT /api/sharepoint/default { driveId, itemId } { default: Target }
DELETE /api/sharepoint 204 (fjerner også alle egne kontoer)
DELETE /api/sharepoint/me 204
GET /api/sharepoint/browse?as=org|me&q=&site=&drive=&item=&next= { entries: [{ kind, id, name, webUrl, driveId }], next, here: Target }
POST /api/sharepoint/folders { as, driveId, parentId, name } 201 { folder: Target }
GET /api/envelopes/{id}/sharepoint { filing }
PUT /api/envelopes/{id}/sharepoint { mode: "default" | "own" | "off", driveId?, itemId? } { filing }; 409 når den er lastet opp
POST /api/envelopes/{id}/sharepoint/retry { filing }

Target = { driveId, itemId, siteName, path, webUrl }. filing = { mode, target, default, mine, chosenBy, uploadedAt, fileUrl, uploadedPath, usedDefault, note, attempts, nextAttemptAt, lastError, failedAt }. 409 med code: "microsoft_account_required" betyr at personen må koble til sin egen Microsoft-konto først; microsoft_reconnect at innloggingen er utløpt.

Plattform-API (bare Relation OS)

Brukes av Relation OS for å aktivere, følge og avslutte koblingen til en organisasjon. Alle kall har Authorization: Bearer <PLATFORM_KEY>; feil eller manglende nøkkel er 401. Uten PLATFORM_KEY på serveren finnes ikke rutene (404). Pakker er komet, planet eller stjerne.

Metode Sti Kropp Svar
POST /api/platform/organizations { relationOsCompanyId, relationOsTenant?, name, orgNumber?, osPackage, webhookUrl?, rotateKey? } se under
PUT /api/platform/organizations/{id}/plan { osPackage } 204. Planen settes til relation_os med pakken (opprettet av relation_os). 409 hvis organisasjonen ikke er koblet
DELETE /api/platform/organizations/{id}/link 204. Koblingen avsluttes, planen går til Løs vekt (hvis den var relation_os), Relation OS-nøkkelen tilbakekalles og webhooken skrus av. Organisasjonen, brukerne og dokumentene blir værende. Å koble fra noe som ikke er koblet gjør ingenting

POST /api/platform/organizations er idempotent på relationOsCompanyId:

  • Nytt selskap, ukjent organisasjonsnummer: 201 { status: "linked", organizationId, apiKey, webhookSecret? }. Organisasjonen opprettes på planen relation_os, med en tjenestebruker «Relation OS» (administrator) som eier API-nøkkelen og er reserveavsender. webhookSecret følger med når webhookUrl er gitt. Nøkkelen og hemmeligheten vises bare her.
  • Allerede koblet: 200 { status: "linked", organizationId } uten nye hemmeligheter. Med rotateKey: true byttes API-nøkkelen (og webhook-hemmeligheten når webhookUrl er gitt), og de nye verdiene returneres. Mangler organisasjonen en nøkkel, for eksempel rett etter en godkjenning, utstedes den nå.
  • Organisasjonsnummeret finnes på en organisasjon som ikke er koblet: 202 { status: "pending_approval" }. En administrator i organisasjonen får en forespørsel på Organisasjon-siden og godkjenner eller avviser. Ved godkjenning kobles selskapet og planen settes til relation_os; neste kall med samme relationOsCompanyId gir 200 med nøkkelen. Ved avvisning svarer kallet 403 { status: "rejected" } i sju dager, deretter kan Relation OS spørre på nytt.
  • 409 når organisasjonsnummeret bare finnes på organisasjoner koblet til andre selskaper, 422 for ugyldig innhold.

Administratorenes side av godkjenningen (sesjon, rolle admin):

Metode Sti Kropp Svar
GET /api/organization/link-requests { linkRequests: [{ id, companyName, osPackage, packageName, requestedAt }] }
POST /api/organization/link-requests/{id} { decision: "approve" | "reject" } 204; ukjent, avgjort eller fremmed forespørsel er 404