{"openapi":"3.1.0","info":{"title":"Tidvis Sign API","version":"1.3.0","description":"Public REST API v1 för e-signering med Tidvis Sign. OAuth2 client-credentials, scope-baserad åtkomst, idempotency, HMAC-signerade webhooks. Ingår i Enterprise-planen.\n\nBas-URL i produktion: `https://tidvis.se/api/public/v1`\n\n**Unified model:** Avtal skapade via API lever i samma tabell som avtal skapade i plattformen. De syns direkt i webb-UI:t under fliken *Via integration* i `/app/sign/dokument`, delar reminder-cron, arkiv och 18-månaders retention med native-avtal, och kan öppnas, patchas och avbrytas både via API och UI. Deltagarnas signeringslänk är alltid `https://tidvis.se/sign/{token}` — samma flöde som avtal skapade i plattformen.\n\n**Versionering (v1.3):** När ett `POST /agreements` skapas med samma `(external_source, external_id)` som ett tidigare avtal blir det automatiskt en ny version av kedjan. Fältet `version` bumpas, `replaces_document_id` pekar på förra raden, och den tidigare markeras `superseded_at` — samt auto-cancel:as om den fortfarande var öppen. Om förra versionen var utskickad (`sent/viewed/partially_signed`) kopieras avsändare + recipients in, och när HubSpot (eller annan integration) sen laddar upp PDF via `PUT /agreements/{id}/documents/main` triggas automatiskt `send` — ingen extra `/lifecycle` behövs. `GET /agreements` returnerar default bara aktuella versioner (`?group=latest`). Använd `?group=all` för att platta ut kedjor, eller `GET /agreements/{id}/versions` för full historik.","contact":{"name":"Tidvis","url":"https://tidvis.se/utvecklare/api"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://tidvis.se/api/public/v1","description":"Production"}],"tags":[{"name":"OAuth","description":"Token-utgivning"},{"name":"Agreements","description":"Avtal, deltagare, livscykel"},{"name":"Comments & chat","description":"Kommentarer och deltagar-chat"},{"name":"Webhooks","description":"Push-notiser med HMAC-signering"},{"name":"Clients","description":"API-klienter och nycklar"},{"name":"Sub-accounts","description":"Underkonton, medlemmar, parent-access"},{"name":"Agreement templates","description":"AI-byggda mallar från dina egna exempelavtal"},{"name":"Agreement generations","description":"Genererade avtal från mallar (DOCX / Sign)"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access-token från `POST /oauth/access-token`. Skicka som `Authorization: Bearer <token>`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_request","unauthorized","plan_required","bankid_disabled","forbidden","not_found","conflict","rate_limited","server_error"]},"message":{"type":"string"},"details":{}}}}},"AgreementParty":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["signer","reviewer"]},"order":{"type":"integer"},"job_title":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"personal_id_masked":{"type":"string","nullable":true},"notifications_enabled":{"type":"boolean"},"status":{"type":"string","enum":["pending","signed","declined","delegated"]}}},"Agreement":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","sent","partially_signed","signed","completed","cancelled","declined","expired"]},"title":{"type":"string"},"message":{"type":"string","nullable":true},"expires_at":{"type":"string","format":"date-time","nullable":true},"parties":{"type":"array","items":{"$ref":"#/components/schemas/AgreementParty"}},"external_id":{"type":"string","nullable":true},"external_source":{"type":"string","nullable":true},"external_url":{"type":"string","format":"uri","nullable":true},"metadata":{"type":"object","additionalProperties":true,"nullable":true},"version":{"type":"integer","minimum":1,"description":"Versionsnummer i kedjan (1 = första)."},"replaces_document_id":{"type":"string","format":"uuid","nullable":true,"description":"Pekar på det avtal som denna version ersätter."},"superseded_at":{"type":"string","format":"date-time","nullable":true,"description":"Sätts när avtalet ersatts av en nyare version."},"versions":{"type":"array","nullable":true,"description":"Hela versionskedjan (endast med i responsen när avtalet ingår i en kedja, dvs `version > 1` eller är superseded).","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"status":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"is_current":{"type":"boolean"}}}},"auto_reminders_enabled":{"type":"boolean"},"reminder_interval_days":{"type":"integer"},"max_reminders":{"type":"integer"},"signed_pdf_url":{"type":"string","format":"uri","nullable":true,"description":"Short-lived signed URL to the stamped final PDF (only present after completion)."},"signed_at":{"type":"string","format":"date-time","nullable":true},"signed_sha256":{"type":"string","nullable":true,"description":"Hex SHA-256 of the stamped final PDF."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"SubAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parent_account_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"org_number":{"type":"string","nullable":true},"plan":{"type":"string"},"inherit_parent_admins":{"type":"boolean"},"archived_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"SubAccountMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","nullable":true},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]},"status":{"type":"string","enum":["active","invited"]},"created_at":{"type":"string","format":"date-time"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"secret_preview":{"type":"string","description":"First 8 chars of the signing secret"},"created_at":{"type":"string","format":"date-time"}}},"ApiClient":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["active","revoked"]},"scopes":{"type":"array","items":{"type":"string"}},"last_used_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"revoked_at":{"type":"string","format":"date-time","nullable":true}}},"AgreementTemplateSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["processing","ready","failed","active","draft"]},"language":{"type":"string"},"currency":{"type":"string"},"source_uploads_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"AgreementTemplate":{"allOf":[{"$ref":"#/components/schemas/AgreementTemplateSummary"},{"type":"object","properties":{"schema_version":{"type":"integer"},"schema":{"type":"object","description":"Full template schema — parts, modules, pricing, clauses.","additionalProperties":true}}}]},"AgreementGeneration":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"template_id":{"type":"string","format":"uuid"},"agreement_number":{"type":"string"},"monthly_total_ore":{"type":"integer","description":"Total månadsbelopp i öre inkl. moms"},"sign_document_id":{"type":"string","format":"uuid","nullable":true},"storage_path":{"type":"string","nullable":true},"form_state":{"type":"object","additionalProperties":true},"created_at":{"type":"string","format":"date-time"}}}}},"paths":{"/oauth/access-token":{"post":{"tags":["OAuth"],"summary":"Issue access token (client-credentials)","description":"Returnerar en bearer-token (TTL 1h). Rate-limited per IP (10/min) och per client_id (30/min).","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"}}},"example":{"client_id":"tvs_live_8f3a9c2b1d","client_secret":"sk_live_7e1d4f6a9c2b3e5f8a0c1b2d4e6f7a8b"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","example":3600},"scope":{"type":"string"}}},"example":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0dnNfbGl2ZV84ZjNhOWMyYjFkIiwic2NvcGUiOiJhZ3JlZW1lbnRzOnJlYWQgYWdyZWVtZW50czpjcmVhdGUiLCJleHAiOjE3NTAzNjQwMDB9.signature","token_type":"Bearer","expires_in":3600,"scope":"agreements:read agreements:create agreements:send"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid client credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Invalid client credentials"}}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["OAuth"],"summary":"Revoke current access token","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Revoked"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements":{"get":{"tags":["Agreements"],"summary":"List agreements","description":"List agreements owned by the calling client. Default returnerar bara aktuella versioner (`group=latest`); använd `group=all` för att inkludera superseded versioner (t.ex. tidigare avtal som ersatts av en ny HubSpot-omsändning). Stödjer filtrering på `external_id`, `external_source` och `status`.","security":[{"bearerAuth":["agreements:read"]}],"parameters":[{"name":"external_id","in":"query","schema":{"type":"string"},"description":"Match by external id (e.g. HubSpot deal id)"},{"name":"external_source","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","sent","partially_signed","completed","cancelled","declined","expired"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"group","in":"query","schema":{"type":"string","enum":["latest","all"],"default":"latest"},"description":"`latest` (default) döljer superseded versioner; `all` plattar ut hela kedjan."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"agreements":{"type":"array","items":{"$ref":"#/components/schemas/Agreement"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Agreements"],"summary":"Create draft agreement","security":[{"bearerAuth":["agreements:create"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Client-supplied key (≤ 80 chars). The same key with the same body within 24h returns the original response.","schema":{"type":"string","maxLength":80}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","minLength":1,"maxLength":255},"message":{"type":"string","maxLength":2000},"expires_at":{"type":"string","format":"date-time"},"callback_url":{"type":"string","format":"uri","maxLength":500},"metadata":{"type":"object","additionalProperties":true},"bankid_required":{"type":"boolean"},"bankid_identify_required":{"type":"boolean"},"external_id":{"type":"string","maxLength":255},"external_source":{"type":"string","maxLength":64,"pattern":"^[a-z0-9_-]+$"},"external_url":{"type":"string","format":"uri","maxLength":1000},"sender":{"type":"object","required":["email"],"description":"Avsändare — autosigneras vid send (samma beteende som UI-flödet). Läggs till som is_sender=true och skickar inget signeringsmail.","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":255}}},"auto_reminders":{"type":"object","description":"Automatic reminder settings (defaults: enabled=true, interval_days=3, max_reminders=3). Reminders run daily via cron; requires the account-level auto-reminder toggle to also be enabled.","properties":{"enabled":{"type":"boolean","default":true},"interval_days":{"type":"integer","minimum":1,"maximum":30,"default":3},"max_reminders":{"type":"integer","minimum":0,"maximum":20,"default":3}}}}},"example":{"title":"Konsultavtal Q3 2026 – Acme AB","message":"Hej! Vänligen signera bifogat konsultavtal senast 30 juni.","expires_at":"2026-06-30T23:59:59Z","bankid_required":true,"external_id":"deal_38291","external_source":"hubspot","sender":{"name":"Anna Andersson","email":"anna@tidvis.se"},"metadata":{"deal_owner":"anna@tidvis.se","region":"SE"},"auto_reminders":{"enabled":true,"interval_days":3,"max_reminders":3}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agreement"},"example":{"id":"a1b2c3d4-1111-4aaa-9bbb-000000000001","status":"draft","title":"Konsultavtal Q3 2026 – Acme AB","message":"Hej! Vänligen signera bifogat konsultavtal senast 30 juni.","expires_at":"2026-06-30T23:59:59Z","parties":[],"external_id":"deal_38291","external_source":"hubspot","external_url":null,"metadata":{"deal_owner":"anna@tidvis.se","region":"SE"},"created_at":"2026-06-20T10:00:00Z","updated_at":"2026-06-20T10:00:00Z"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Enterprise-planen krävs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"plan_required","message":"The Public API v1 is only available on the Enterprise plan."}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreements"],"summary":"Get agreement","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agreement"},"example":{"id":"a1b2c3d4-1111-4aaa-9bbb-000000000001","status":"signed","title":"Konsultavtal Q3 2026 – Acme AB","message":null,"expires_at":"2026-06-30T23:59:59Z","parties":[{"id":"b2c3d4e5-2222-4bbb-9ccc-000000000010","name":"Anna Andersson","email":"anna@acme.se","role":"signer","order":0,"job_title":"VD","phone":null,"personal_id_masked":"19800101-XXXX","notifications_enabled":true,"status":"signed"},{"id":"b2c3d4e5-2222-4bbb-9ccc-000000000011","name":"Bo Bengtsson","email":"bo@acme.se","role":"signer","order":1,"job_title":"CFO","phone":null,"personal_id_masked":"19750505-XXXX","notifications_enabled":true,"status":"signed"}],"external_id":"deal_38291","external_source":"hubspot","external_url":null,"metadata":{"deal_owner":"anna@tidvis.se"},"created_at":"2026-06-20T10:00:00Z","updated_at":"2026-06-21T14:23:11Z"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Agreements"],"summary":"Update agreement metadata and reminder settings","description":"Patch a live or draft agreement. `title`, `message`, `metadata`, `callback_url`, `external_url`, `sender` och `auto_reminders.*` can be updated. `sender` kan bara ändras i status `draft` (autosigneras vid send). Rejected with 409 for terminal statuses (completed, cancelled, declined, deleted, expired).","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":255},"message":{"type":"string","maxLength":2000,"nullable":true},"callback_url":{"type":"string","format":"uri","maxLength":500,"nullable":true},"external_url":{"type":"string","format":"uri","maxLength":1000,"nullable":true},"metadata":{"type":"object","additionalProperties":true},"sender":{"type":"object","nullable":true,"required":["email"],"description":"Sätter/uppdaterar avsändaren som autosigneras vid send. Skicka null för att ta bort. Endast i status draft.","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":255}}},"auto_reminders":{"type":"object","properties":{"enabled":{"type":"boolean"},"interval_days":{"type":"integer","minimum":1,"maximum":30},"max_reminders":{"type":"integer","minimum":0,"maximum":20}}}}},"example":{"message":"Uppdaterat: signera senast 30 juni!","auto_reminders":{"enabled":true,"interval_days":2,"max_reminders":5}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agreement"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Agreements"],"summary":"Delete draft agreement","security":[{"bearerAuth":["agreements:create"]}],"responses":{"204":{"description":"Deleted"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/versions":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreements"],"summary":"Get version chain","description":"Returnerar hela versionskedjan för avtalet, sorterat på version ASC. Fungerar även när det anropande id:t inte är aktuell version.","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"agreement_id":{"type":"string","format":"uuid"},"versions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"status":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"is_current":{"type":"boolean"}}}}}},"example":{"agreement_id":"def-...","versions":[{"id":"abc-...","version":1,"status":"cancelled","created_at":"2026-06-20T10:00:00Z","is_current":false},{"id":"def-...","version":2,"status":"sent","created_at":"2026-06-22T09:00:00Z","is_current":true}]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/signed-pdf":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreements"],"summary":"Get signed (stamped) PDF URL","description":"Returns a short-lived signed URL to the final stamped PDF (with per-page footer, verification page, party details incl. BankID metadata, SHA-256 hash and QR code to public verification). Generated automatically when the last participant signs. Returns 409 if the agreement is not completed yet.","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"expires_in":{"type":"integer","example":3600}}},"example":{"url":"https://...signed.pdf?token=...","expires_in":3600}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/lifecycle":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreements"],"summary":"Send or cancel an agreement","description":"`send` kräver `agreements:send`, `cancel` kräver `agreements:cancel`.","security":[{"bearerAuth":["agreements:send","agreements:cancel"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["send","cancel"]},"sender":{"type":"object","required":["email"],"description":"Endast vid action=send. Avsändare som autosigneras. Vinner över sender som satts på draften.","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":255}}}}},"examples":{"send":{"summary":"Skicka ut för signering","value":{"action":"send"}},"sendWithSender":{"summary":"Skicka med explicit avsändare (autosigneras)","value":{"action":"send","sender":{"name":"Anna Andersson","email":"anna@tidvis.se"}}},"cancel":{"summary":"Avbryt avtalet","value":{"action":"cancel"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"}}},"example":{"ok":true,"status":"sent"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/participants":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreements"],"summary":"Add participant (draft or live agreement)","description":"Add a signer or reviewer. For agreements in `sent`/`partially_signed`, the new participant is issued a signing link and an invite email is sent immediately. For drafts, they are added without a link (link generated on `send`).","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"type":"string","format":"email","maxLength":255},"role":{"type":"string","enum":["signer","reviewer"],"default":"signer"},"order":{"type":"integer","minimum":0,"maximum":100},"job_title":{"type":"string","maxLength":200},"phone":{"type":"string","maxLength":40},"personal_id_masked":{"type":"string","maxLength":40},"notifications_enabled":{"type":"boolean"}}},"example":{"name":"Anna Andersson","email":"anna@acme.se","role":"signer","order":0,"job_title":"VD","phone":"+46701234567","notifications_enabled":true}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgreementParty"},"example":{"id":"b2c3d4e5-2222-4bbb-9ccc-000000000010","name":"Anna Andersson","email":"anna@acme.se","role":"signer","order":0,"job_title":"VD","phone":"+46701234567","personal_id_masked":null,"notifications_enabled":true,"status":"pending"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/participants/{pid}/decline":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"pid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreements"],"summary":"Decline on behalf of a participant","security":[{"bearerAuth":["agreements:cancel"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/participants/{pid}/delegate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"pid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreements"],"summary":"Delegate participant to another person","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string","maxLength":200},"email":{"type":"string","format":"email","maxLength":255},"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/participants/{pid}/notifications":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"pid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"tags":["Agreements"],"summary":"Toggle reminder notifications for a participant","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/download":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreements"],"summary":"Download signed PDF","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"Signed PDF binary","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/events":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreements"],"summary":"List audit events for an agreement","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/documents/main":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreements"],"summary":"Attach the main PDF document to a draft","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/chat":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Comments & chat"],"summary":"List chat messages","security":[{"bearerAuth":["agreements:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Comments & chat"],"summary":"Post a chat message","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"sender_label":{"type":"string","maxLength":200},"sender_email":{"type":"string","format":"email","maxLength":255},"participant_id":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/comments":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Comments & chat"],"summary":"List comments","security":[{"bearerAuth":["agreements:read"]}],"parameters":[{"name":"include_resolved","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"comments":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Comments & chat"],"summary":"Post a comment","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"page":{"type":"integer","minimum":1,"maximum":2000},"anchor_x":{"type":"number","minimum":0,"maximum":1},"anchor_y":{"type":"number","minimum":0,"maximum":1},"author_label":{"type":"string","maxLength":200},"author_email":{"type":"string","format":"email","maxLength":255},"participant_id":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreements/{id}/comments/{commentId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"tags":["Comments & chat"],"summary":"Resolve or reopen a comment","security":[{"bearerAuth":["agreements:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["resolved"],"properties":{"resolved":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"summary":"Register a webhook","description":"Returns the signing secret ONCE in `secret`. Store it — used to verify `X-Tidvis-Signature` (HMAC-SHA256 over the raw body).\n\n### Exempel-callback från Tidvis\n\n```http\nPOST /your-webhook HTTP/1.1\nContent-Type: application/json\nX-Tidvis-Event: agreement.signed\nX-Tidvis-Delivery: 9f1c3a7e-2b4d-4e6a-8c1f-1234567890ab\nX-Tidvis-Signature: sha256=8a2c…d4f9\n\n{\n  \"event\": \"agreement.signed\",\n  \"event_type\": \"agreement.signed\",\n  \"delivery_id\": \"9f1c3a7e-2b4d-4e6a-8c1f-1234567890ab\",\n  \"created_at\": \"2026-06-20T12:00:00Z\",\n  \"agreement_id\": \"a1b2c3d4-1111-4aaa-9bbb-000000000001\",\n  \"status\": \"signed\",\n  \"participant\": {\n    \"id\": \"b2c3d4e5-2222-4bbb-9ccc-000000000010\",\n    \"email\": \"anna@acme.se\"\n  },\n  \"data\": {\n    \"agreement_id\": \"a1b2c3d4-1111-4aaa-9bbb-000000000001\",\n    \"status\": \"signed\",\n    \"participant\": {\n      \"id\": \"b2c3d4e5-2222-4bbb-9ccc-000000000010\",\n      \"email\": \"anna@acme.se\"\n    }\n  }\n}\n```\n\nVerifiera signaturen i Node:\n\n```ts\nimport { createHmac, timingSafeEqual } from 'crypto';\n\nconst header = req.headers['x-tidvis-signature']; // 'sha256=…'\nconst signature = header.replace(/^sha256=/, '');\nconst expected = createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex');\nif (!timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) throw new Error('bad signature');\n```","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","maxLength":500},"events":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string","enum":["agreement.sent","agreement.viewed","agreement.identified","agreement.signed","agreement.completed","agreement.cancelled","agreement.declined","agreement.delegated","participant.notifications_changed","agreement.chat_message","agreement.comment_created","agreement.comment_resolved","agreement.expired","agreement.pdf_replaced","agreement.superseded","*"]}}}},"example":{"url":"https://acme.se/webhooks/tidvis","events":["agreement.signed","agreement.completed","agreement.cancelled"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"Shown once"}}}]},"example":{"id":"c3d4e5f6-3333-4ccc-9ddd-000000000100","url":"https://acme.se/webhooks/tidvis","events":["agreement.signed","agreement.completed","agreement.cancelled"],"secret_preview":"whsec_8a","secret":"whsec_8a2c4f6e1d3b5a7c9e0f2d4b6a8c1e3f5a7b9c0d","created_at":"2026-06-20T10:05:00Z"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients":{"get":{"tags":["Clients"],"summary":"List API clients","security":[{"bearerAuth":["clients:manage"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"clients":{"type":"array","items":{"$ref":"#/components/schemas/ApiClient"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Clients"],"summary":"Create API client","description":"Returns the client_secret ONCE.","security":[{"bearerAuth":["clients:manage"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"scopes":{"type":"array","items":{"type":"string"},"maxItems":20}}},"example":{"name":"HubSpot-integration (produktion)","scopes":["agreements:read","agreements:create","agreements:send"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiClient"},{"type":"object","properties":{"client_secret":{"type":"string","description":"Shown once"}}}]},"example":{"id":"d4e5f6a7-4444-4ddd-9eee-000000000200","client_id":"tvs_live_8f3a9c2b1d","name":"HubSpot-integration (produktion)","status":"active","scopes":["agreements:read","agreements:create","agreements:send"],"last_used_at":null,"created_at":"2026-06-20T10:10:00Z","revoked_at":null,"client_secret":"sk_live_7e1d4f6a9c2b3e5f8a0c1b2d4e6f7a8b"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients/{id}/revoke":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Clients"],"summary":"Revoke API client","security":[{"bearerAuth":["clients:manage"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-templates":{"get":{"tags":["Agreement templates"],"summary":"List agreement templates","description":"Kräver att avtalsmodulen är aktiv på kontot (99 kr/användare/månad).","security":[{"bearerAuth":["templates:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/AgreementTemplateSummary"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Avtalsmodulen ej aktiv","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"plan_required","message":"Avtalsmodulen är inte aktiv för detta konto (99 kr/användare/månad)."}}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Agreement templates"],"summary":"Create template from 2–10 example agreements","description":"Skickar exempelavtal (PDF/DOCX) — AI extraherar produkter, prislogik och klausuler. Multipart eller JSON med base64.","security":[{"bearerAuth":["templates:manage"]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["name","files"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"files":{"type":"array","items":{"type":"string","format":"binary"},"minItems":2,"maxItems":10}}}},"application/json":{"schema":{"type":"object","required":["name","files"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"files":{"type":"array","minItems":2,"maxItems":10,"items":{"type":"object","required":["filename","mime","pdf_base64"],"properties":{"filename":{"type":"string"},"mime":{"type":"string"},"pdf_base64":{"type":"string"}}}}}},"example":{"name":"Konsultavtal SaaS 2026","files":[{"filename":"acme-2025.pdf","mime":"application/pdf","pdf_base64":"JVBERi0xLjQKJ..."},{"filename":"beta-2025.pdf","mime":"application/pdf","pdf_base64":"JVBERi0xLjQKJ..."}]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["ready","failed"]},"extraction_error":{"type":"string","nullable":true}}},"example":{"id":"c3d4e5f6-3333-4ccc-9ddd-000000000700","status":"ready","extraction_error":null}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreement templates"],"summary":"Get one template with full schema and source files","security":[{"bearerAuth":["templates:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/AgreementTemplate"},"sources":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Agreement templates"],"summary":"Delete template and its source files","security":[{"bearerAuth":["templates:manage"]}],"responses":{"204":{"description":"Deleted"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-templates/{id}/generate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Agreement templates"],"summary":"Generate a new agreement from this template","description":"Utan `send_for_signing`: returnerar DOCX inline (base64). Med `send_for_signing: true` + `recipients`: renderar PDF, skapar en Sign-draft, returnerar `sign_document_id`.","security":[{"bearerAuth":["generations:create"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["form"],"properties":{"form":{"type":"object","required":["customer","selections","binding"],"properties":{"customer":{"type":"object","additionalProperties":{"type":"string"}},"selections":{"type":"array","items":{"type":"object","required":["partId","moduleId","quantity"],"properties":{"partId":{"type":"string"},"moduleId":{"type":"string"},"quantity":{"type":"integer","minimum":0,"maximum":10000}}}},"binding":{"type":"integer","enum":[12,24,36]},"startDate":{"type":"string"},"extraNotes":{"type":"string","maxLength":5000}}},"send_for_signing":{"type":"boolean"},"title":{"type":"string"},"message":{"type":"string"},"signature_method":{"type":"string","enum":["click","draw","bankid"]},"recipients":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"role":{"type":"string","enum":["signer","reviewer"]}}}}}},"example":{"form":{"customer":{"company":"Acme AB","orgnr":"556677-8899","contact":"Anna Andersson","email":"anna@acme.se"},"selections":[{"partId":"seats","moduleId":"pro","quantity":5}],"binding":24,"startDate":"2026-07-01"},"send_for_signing":true,"signature_method":"bankid","recipients":[{"email":"anna@acme.se","name":"Anna Andersson"}]}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"generation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agreement_number":{"type":"string"},"monthly_total_ore":{"type":"integer"},"docx_filename":{"type":"string"},"docx_base64":{"type":"string"}}}}},{"type":"object","properties":{"sign_document_id":{"type":"string","format":"uuid"},"agreement_number":{"type":"string"},"next_step":{"type":"string"}}}]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-generations":{"get":{"tags":["Agreement generations"],"summary":"List generated agreements","security":[{"bearerAuth":["generations:read"]}],"parameters":[{"name":"template_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"generations":{"type":"array","items":{"$ref":"#/components/schemas/AgreementGeneration"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-generations/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreement generations"],"summary":"Get one generation","security":[{"bearerAuth":["generations:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"generation":{"$ref":"#/components/schemas/AgreementGeneration"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agreement-generations/{id}/download":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Agreement generations"],"summary":"Get a signed download URL for the generated PDF (10 min TTL)","description":"Endast tillgängligt om genereringen kopplats till ett Sign-dokument (har `storage_path`). DOCX-genereringar returneras inline direkt vid `/generate`.","security":[{"bearerAuth":["generations:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"expires_in":{"type":"integer"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sub-accounts":{"get":{"tags":["Sub-accounts"],"summary":"List sub-accounts under the parent","description":"Endast tokens utgivna på huvudkontot (parent) får anropa sub-account-endpoints.","security":[{"bearerAuth":["sub_accounts:read"]}],"parameters":[{"name":"include_archived","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"sub_accounts":{"type":"array","items":{"$ref":"#/components/schemas/SubAccount"}},"license":{"type":"object","properties":{"status":{"type":"string","enum":["active","past_due","canceled","missing"]},"seats":{"type":"integer"},"used":{"type":"integer"},"expires_at":{"type":"string","format":"date-time","nullable":true}}}}},"example":{"sub_accounts":[{"id":"e5f6a7b8-5555-4eee-9fff-000000000300","parent_account_id":"f6a7b8c9-6666-4fff-9aaa-000000000001","name":"Acme Bygg AB","org_number":"556677-8899","plan":"pro","inherit_parent_admins":true,"archived_at":null,"created_at":"2026-05-01T08:00:00Z"},{"id":"e5f6a7b8-5555-4eee-9fff-000000000301","parent_account_id":"f6a7b8c9-6666-4fff-9aaa-000000000001","name":"Acme Konsult AB","org_number":"556611-2233","plan":"pro","inherit_parent_admins":false,"archived_at":null,"created_at":"2026-05-15T09:30:00Z"}],"license":{"status":"active","seats":10,"used":4,"expires_at":"2027-05-01T00:00:00Z"}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Sub-accounts"],"summary":"Create sub-account","description":"Kräver aktiv årslicens (`sub_account_license_yearly`). Returnerar 403 `plan_required` om licens saknas eller alla seats är upptagna.","security":[{"bearerAuth":["sub_accounts:manage"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"org_number":{"type":"string","maxLength":32,"nullable":true},"inherit_parent_admins":{"type":"boolean","default":true}}},"example":{"name":"Acme Bygg AB","org_number":"556677-8899","inherit_parent_admins":true}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccount"},"example":{"id":"e5f6a7b8-5555-4eee-9fff-000000000300","parent_account_id":"f6a7b8c9-6666-4fff-9aaa-000000000001","name":"Acme Bygg AB","org_number":"556677-8899","plan":"pro","inherit_parent_admins":true,"archived_at":null,"created_at":"2026-06-20T10:15:00Z"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Licens saknas eller alla seats är upptagna","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"plan_required","message":"Sub-account license required. All seats are currently in use.","details":{"seats":10,"used":10}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sub-accounts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Sub-accounts"],"summary":"Get sub-account","security":[{"bearerAuth":["sub_accounts:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccount"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Sub-accounts"],"summary":"Update sub-account","security":[{"bearerAuth":["sub_accounts:manage"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"org_number":{"type":"string","maxLength":32,"nullable":true},"bankid_unlimited":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccount"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Sub-accounts"],"summary":"Archive sub-account (GDPR — hard-delete after 30 days)","description":"Markeras `archived_at`. Cron `purge-archived-sub-accounts-daily` hard-deletar 30 dagar senare.","security":[{"bearerAuth":["sub_accounts:manage"]}],"responses":{"204":{"description":"Archived"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sub-accounts/{id}/parent-access":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"tags":["Sub-accounts"],"summary":"Toggle whether parent admins inherit access","security":[{"bearerAuth":["sub_accounts:manage"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["inherit_parent_admins"],"properties":{"inherit_parent_admins":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccount"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sub-accounts/{id}/members":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Sub-accounts"],"summary":"List sub-account members","security":[{"bearerAuth":["sub_accounts:members"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/SubAccountMember"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Sub-accounts"],"summary":"Invite member to a sub-account","security":[{"bearerAuth":["sub_accounts:members"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","maxLength":255},"role":{"type":"string","enum":["owner","admin","member"],"default":"member"}}},"example":{"email":"cecilia@acme.se","role":"admin"}}}},"responses":{"201":{"description":"Invitation created","content":{"application/json":{"schema":{"type":"object","properties":{"invitation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string"},"accept_url":{"type":"string","format":"uri"}}}}},"example":{"invitation":{"id":"a7b8c9d0-7777-4aaa-9bbb-000000000400","email":"cecilia@acme.se","role":"admin","accept_url":"https://tidvis.se/invite/accept?token=inv_8a2c4f6e1d3b5a7c9e0f2d4b6a8c1e3f"}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sub-accounts/{id}/members/{memberId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"memberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"tags":["Sub-accounts"],"summary":"Change member role","description":"409 `conflict` returneras om åtgärden lämnar underkontot utan ägare.","security":[{"bearerAuth":["sub_accounts:members"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["owner","admin","member"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountMember"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Sub-accounts"],"summary":"Remove member","description":"409 `conflict` returneras om åtgärden lämnar underkontot utan ägare.","security":[{"bearerAuth":["sub_accounts:members"]}],"responses":{"204":{"description":"Removed"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — missing scope, wrong plan, or sub-account license required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}