API Documentation

Signeum's REST API lets you integrate legally binding document signing directly into your product. Create documents, manage signers, and track status — all through the API.

Base URL

https://api.signeum.se/api/v1

All requests and responses use JSON. Always include the header Content-Type: application/json.

Widget integration?

If you're looking to embed the signing experience in your application, see the Widget Guide.

Concepts & Data Model

Before you start integrating, it helps to understand how Signeum is structured. Here are the core concepts and how they relate to each other.

Organization → Project → Document

Signeum's data model has three levels. An organization is your account and owns all resources. Within the organization, projects group documents and carry settings for branding, signing methods, and notifications. Documents are always created within a project and inherit the project's settings.

Default Projects

Every new organization automatically gets two system projects:

  • Standard Signing — supports methods drawn, typed, and none (simple e-signature)
  • eID Signing — configured for bankid_se (Swedish BankID)

You can create your own projects with custom settings via the API.

Signing Methods

A project uses either standard methods (drawn, typed, none) or eID (bankid_se). You cannot mix standard and eID methods in the same project. For eID projects, signers must have a personalNumber (Swedish personal number).

Project Settings

Each project has settings that affect all documents within it:

  • Branding — logo, colors, and company name in the signing view
  • Email notifications — can be enabled or disabled per project
  • Chat — allow participants to communicate in the signing view
  • Audit log — embed the audit trail in the signed PDF
  • Post-signing — show a message or redirect to a URL after signing
  • Auto-reminder — send a reminder after N days

Document Status

A document goes through the following statuses during its lifecycle:

Status Description
pending The document is created and waiting for the first signer to act
in_progress At least one signer has signed, but not all
processing All signers have signed and the document is being processed before completion
completed All signers have signed — the document is complete
expired The signing deadline has passed without all signatures
cancelled The document has been cancelled by the sender
declined A signer has declined to sign

Multi-tenant Pattern

If you're building a SaaS product and want to offer signing to your customers, you can create one project per customer (tenant). Each project can have its own logo, colors, and company name — so the signing view matches the customer's brand.

White-label Email

Want to send your own emails instead of Signeum's default notifications? Disable email notifications at the project level and listen to webhook events (e.g. document.completed, document.signed). Then send your own emails with your sender address and design.

Signing Order

Participants can be assigned a signingOrder. Signers with a lower order number must sign before the next in line gets access to the document. Participants with the same order number can sign in parallel.

Authentication

All API calls require a valid API key. Keys are created in the organization settings by an owner. Each key is scoped to one organization.

Project-Scoped API Keys

API keys support two access modes:

  • All projects (default) — the key can access every project in the organization. This is the standard behavior.
  • Scoped — the key is restricted to one or more specific projects. Requests to projects outside the allowed list will receive a 403 Forbidden error.

Scoped keys are useful for integrations, CI pipelines, or third-party services that should only access a subset of your projects. You choose the mode when creating the key.

API keys are prefixed with ds_ and sent via the Authorization header:

HEADER Authorization header
Authorization: Bearer ds_your_api_key_here
The API key is only shown once at creation time. Store it securely. If you lose it, you'll need to create a new one.

Rate Limiting

The API allows 100 requests per minute per API key. If the limit is exceeded, status code 429 Too Many Requests is returned.

The response includes a Retry-After header with the number of seconds until the window resets.

Error Handling

All errors are returned with a consistent JSON structure:

ERROR Error format
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "trackingId": "abc-123-def",
    "details": {
      "fields": {
        "name": "Document name is required"
      }
    }
  }
}
Status Code Code Description
400 VALIDATION_ERROR Invalid request or validation error
401 UNAUTHORIZED Missing or invalid API key
403 FORBIDDEN Access denied to the resource
404 NOT_FOUND Resource not found
402 PAYMENT_REQUIRED Payment method required
429 RATE_LIMITED Rate limit exceeded
500 INTERNAL_ERROR Internal server error

Webhooks

Configure webhook endpoints at the project level to receive real-time notifications about document events. Signeum sends a POST request with a JSON payload to your URL for documents created both via the API and the UI.

POST Webhook payload
{
  "eventType": "document.signed",
  "timestamp": "2026-03-16T10:30:00Z",
  "documentId": "d4f5a6b7-...",
  "organizationId": "a1b2c3d4-...",
  "projectId": "e5f6a7b8-...",
  "participant": {
    "name": "Anna Lindström",
    "email": "[email]",
    "role": "signer"
  }
}
Event Description
document.viewed A signer has opened the document
document.signed A signer has signed the document
document.reviewed A reviewer has reviewed the document
document.processing All signers have signed — the document is being processed (PDF compilation)
document.completed All signers have signed — the document is complete
document.failed Document processing failed (e.g. PDF compilation error)
document.cancelled The document has been cancelled
document.expired The signing deadline has passed
document.expiring The signing deadline is approaching (default: within 3 days)
participant.declined A signer has declined to sign
document.analyzed AI analysis has completed (tags, taxonomy, embeddings generated)
document.tags_updated Tags or taxonomy have been added, edited, or removed on a document
chat.message A new chat message on the document
email.bounced An email notification bounced
email.failed An email notification failed to send

Webhook Signatures

Every webhook request is signed with an HMAC-SHA256 signature so you can verify it came from Signeum and hasn't been tampered with. Each organization has a unique webhook secret, available in your organization settings.

Signature Headers

Signeum includes two headers on every webhook request:

Header Description
X-Signeum-Signature HMAC-SHA256 signature in the format sha256=<hex-digest>
X-Signeum-Timestamp Unix timestamp (seconds) when the signature was computed

How to Verify

The signature is computed over <timestamp>.<body> — the timestamp value, a dot, and the raw JSON request body. To verify:

  1. Read the X-Signeum-Timestamp header
  2. Read the raw request body (before any JSON parsing)
  3. Concatenate them as <timestamp>.<body>
  4. Compute HMAC-SHA256 using your organization's webhook secret as the key
  5. Compare the hex digest with the value after sha256= in the signature header
NODE.JS Verification example
import crypto from 'crypto';

function verifyWebhook(secret, body, signatureHeader, timestampHeader) {
  const message = `${timestampHeader}.${body}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');

  const received = signatureHeader.replace('sha256=', '');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(received)
  );
}
PYTHON Verification example
import hmac, hashlib

def verify_webhook(secret, body, signature_header, timestamp_header):
    message = f"{timestamp_header}.{body}"
    expected = hmac.new(
        secret.encode(), message.encode(), hashlib.sha256
    ).hexdigest()

    received = signature_header.replace("sha256=", "")
    return hmac.compare_digest(expected, received)
Always use a constant-time comparison function (like timingSafeEqual or hmac.compare_digest) to prevent timing attacks.

Replay Protection

The timestamp is included in the signed message to prevent replay attacks. You should reject webhooks where the timestamp is more than 5 minutes old:

NODE.JS Timestamp check
const MAX_AGE_SECONDS = 300; // 5 minutes
const now = Math.floor(Date.now() / 1000);
const timestamp = parseInt(req.headers['x-signeum-timestamp']);

if (Math.abs(now - timestamp) > MAX_AGE_SECONDS) {
  return res.status(403).json({ error: 'Webhook timestamp too old' });
}

Managing Your Secret

Your webhook secret is auto-generated when the organization is created. You can view and copy it from the organization settings page, or rotate it via the API:

GET View current secret
curl https://api.signeum.se/api/v1/organizations/{orgId}/webhook-secret \
  -H "Authorization: Bearer ds_your_api_key"

# Response: { "webhookSecret": "a1b2c3d4..." }
POST Rotate secret
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/webhook-secret/rotate \
  -H "Authorization: Bearer ds_your_api_key"

# Response: { "webhookSecret": "e5f6a7b8..." }
Rotating the secret takes effect immediately for all future webhook deliveries. After rotating, copy the new secret from the response and update your receiver as soon as possible. Any deliveries sent between the rotation and your update will use the new secret.

Retry Behavior

If your endpoint returns a non-2xx response or is unreachable, Signeum retries the delivery with increasing delays over a span of several hours.

Attempt Delay
1 Immediate
2 30 seconds
3 2 minutes
4 5 minutes
5 15 minutes
6 30 minutes
7 45 minutes
8 1 hour
9 1.5 hours

After all attempts are exhausted, the delivery is marked as failed.

Response Handling

  • 2xx — Delivery successful, no retry
  • 4xx (except 429) — Permanent failure, no retry. Fix the issue on your end
  • 429 — Rate limited. Signeum respects the Retry-After header
  • 5xx / timeout — Transient failure, retried per the schedule above

Tip

Return a 200 quickly and process the webhook asynchronously. If your endpoint takes too long (over 10 seconds), the request will time out and be retried.

Projects

POST /organizations/:orgId/projects

Create a new project in the organization. Projects are used to group documents and can have separate settings for branding, signing methods, and notifications.

Parameters

Parameter Type Required Description
name string Yes Project name (1–255 characters)
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Customer Contracts" }'
201 Response
{
  "project": {
    "id": "e5f6a7b8-c9d0-4e1f-a2b3-c4d5e6f7a8b9",
    "organizationId": "a1b2c3d4-...",
    "name": "Customer Contracts",
    "isDefault": false,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z",
    "settings": {
      "emailNotificationsEnabled": true,
      "includeAuditInDocument": true,
      "chatEnabled": true,
      "allowedSigningMethods": ["drawn", "typed", "none", "bankid_se"]
    }
  }
}

GET /organizations/:orgId/projects

List all projects in the organization with pagination.

Query parameters

Parameter Type Description
page number Page number (default: 1)
limit number Items per page (default: 20, max: 100)
search string Search by project name
sort string Sort order, e.g. createdAt:desc
GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "projects": [
    {
      "id": "e5f6a7b8-...",
      "organizationId": "a1b2c3d4-...",
      "name": "Customer Contracts",
      "isDefault": false,
      "createdAt": "2026-03-16T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1
  }
}

GET /organizations/:orgId/projects/:projectId

Get details for a specific project including settings.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId} \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "project": {
    "id": "e5f6a7b8-c9d0-4e1f-a2b3-c4d5e6f7a8b9",
    "organizationId": "a1b2c3d4-...",
    "name": "Customer Contracts",
    "isDefault": false,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z",
    "creator": {
      "type": "user",
      "name": "Richard Barkestam",
      "email": "[email]",
      "userId": "u1a2b3c4-..."
    },
    "settings": {
      "emailNotificationsEnabled": true,
      "includeAuditInDocument": true,
      "chatEnabled": true,
      "allowedSigningMethods": ["drawn", "typed", "none"]
    }
  }
}

Documents

POST /organizations/:orgId/projects/:projectId/documents

Create a new document with participants and send it for signing. The document can be uploaded as a base64-encoded PDF, fetched from a URL, created from a template, or referenced via a temp session (for large files uploaded separately).

Parameters

Parameter Type Required Description
name string Yes Document name (1–255 characters)
document object Yes* PDF upload. Either { type: "base64", content: "..." } or { type: "url", url: "..." }
templateId string Yes* UUID of a template to create the document from. Alternative to document
sessionId string Yes* UUID of a temp session containing an uploaded PDF. Alternative to document. Use this for large files uploaded via the temp session flow
participants array Yes List of participants (1–50). See participant object below
signingDeadline string No ISO 8601 date. Max 30 days ahead
allowedSigningMethods array No Allowed signing methods: drawn, typed, none. Ignored for eID projects (BankID is configured at the project level)
autoReminderDays number No Send automatic reminder after N days (1–30)
roleMapping object No Mapping of template roles to participants (for template-based creation)

* Either document, templateId, or sessionId must be provided.

Participant object

Parameter Type Required Description
name string Yes Participant's name
email string Yes Email address
role string Yes signer or reviewer
signingOrder number No Signing order (positive integer)
language string No sv or en (default: en)
otpEnabled boolean No Require OTP verification via email (default: false)
personalNumber string No Swedish personal number (12 digits, YYYYMMDDXXXX). Required for signers in eID projects (BankID)
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Service Agreement 2026",
    "document": {
      "type": "base64",
      "content": "JVBERi0xLjQK..."
    },
    "participants": [
      {
        "name": "Anna Lindström",
        "email": "[email]",
        "role": "signer",
        "signingOrder": 1,
        "language": "sv"
      },
      {
        "name": "Erik Johansson",
        "email": "[email]",
        "role": "signer",
        "signingOrder": 2,
        "language": "sv"
      }
    ],
    "signingDeadline": "2026-04-15T23:59:59Z"
  }'
201 Response
{
  "document": {
    "id": "d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8",
    "projectId": "e5f6a7b8-...",
    "organizationId": "a1b2c3d4-...",
    "name": "Service Agreement 2026",
    "status": "pending",
    "createdAt": "2026-03-16T10:00:00Z",
    "participants": [
      {
        "id": "p1a2b3c4-...",
        "name": "Anna Lindström",
        "email": "[email]",
        "role": "signer",
        "signingOrder": 1,
        "status": "pending"
      }
    ],
    "signingUrls": [
      {
        "participantId": "p1a2b3c4-...",
        "name": "Anna Lindström",
        "email": "[email]",
        "role": "signer",
        "signingUrl": "https://app.signeum.se/sign/abc123..."
      }
    ]
  }
}

GET /organizations/:orgId/projects/:projectId/documents

List documents in a project with pagination and filtering.

Query parameters

Parameter Type Description
page number Page number (default: 1)
limit number Items per page (default: 20, max: 100)
status string Filter by status: pending, in_progress, completed, expired, cancelled
sort string Sort order, e.g. createdAt:desc
GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents?status=pending&limit=10 \
  -H "Authorization: Bearer ds_your_api_key"

GET /organizations/:orgId/projects/:projectId/documents/:documentId

Get details for a specific document including participants and their status.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId} \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "document": {
    "id": "d4f5a6b7-...",
    "projectId": "e5f6a7b8-...",
    "organizationId": "a1b2c3d4-...",
    "name": "Service Agreement 2026",
    "status": "in_progress",
    "createdAt": "2026-03-16T10:00:00Z",
    "signingDeadline": "2026-04-15T23:59:59Z",
    "creator": {
      "type": "user",
      "name": "Richard Barkestam",
      "email": "[email]",
      "userId": "u1a2b3c4-..."
    },
    "participants": [
      {
        "id": "p1a2b3c4-...",
        "name": "Anna Lindström",
        "email": "[email]",
        "role": "signer",
        "signingOrder": 1,
        "status": "signed",
        "signedAt": "2026-03-16T14:30:00Z",
        "signatureMode": "drawn"
      },
      {
        "id": "p2b3c4d5-...",
        "name": "Erik Johansson",
        "email": "[email]",
        "role": "signer",
        "signingOrder": 2,
        "status": "pending"
      }
    ]
  }
}

PUT /organizations/:orgId/projects/:projectId/documents/:documentId/cancel

Cancel a document that hasn't been completed yet. All pending signers will be notified.

PUT Example request
curl -X PUT https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId}/cancel \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Agreement needs to be updated" }'

GET /organizations/:orgId/projects/:projectId/documents/:documentId/download

Get a signed URL to download the signed document (PDF). Available when the document has status completed.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId}/download \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "downloadUrl": "https://storage.signeum.se/signed/...",
  "expiresAt": "2026-03-16T11:00:00Z"
}

POST /organizations/:orgId/projects/:projectId/documents/:documentId/send-reminder

Send a reminder to all pending signers on a document. Optionally include a custom message that will be shown in the reminder email.

Parameters

Parameter Type Required Description
customMessage string No Optional message to include in the reminder email
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId}/send-reminder \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "customMessage": "Please sign the agreement before Friday." }'
200 Response
{
  "sent": 1,
  "recipients": [
    {
      "id": "p2b3c4d5-...",
      "name": "Erik Johansson",
      "email": "[email]"
    }
  ]
}

POST /organizations/:orgId/projects/:projectId/documents/:documentId/analyze

Trigger asynchronous AI analysis on an existing document. Generates tags, taxonomy classification, and text embeddings. The analysis runs in the background — poll the status endpoint to check progress.

Parameters

Parameter Type Required Description
force boolean No Re-analyze even if the document already has results (default: false)
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId}/analyze \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "force": false }'
202 Response
{
  "jobId": "abc-123",
  "status": "processing"
}
Status Code Description
202 Analysis job enqueued
409 Analysis already in progress, or already completed (use force: true to override)
404 Document not found

Webhook

When analysis completes, a document.analyzed webhook event is emitted.

GET /organizations/:orgId/projects/:projectId/documents/:documentId/analyze/status

Check the analysis status for a document.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{documentId}/analyze/status \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "status": "completed",
  "analyzedAt": "2026-03-16T10:05:00Z"
}
Status value Description
not_analyzed Analysis has not been triggered
processing Analysis is running
completed Analysis finished — tags and embeddings are available
failed Analysis failed (includes error field)

GET /organizations/:orgId/projects/:projectId/documents/:docId/risk

Get AI-generated risk flags and sign summary for a document. Requires the document to have been analyzed first via the Analyze document endpoint.

Authentication

Requires a valid API key or session token via the Authorization header. The requesting user must have at least the user role in the organization.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{docId}/risk \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "riskFlags": [
    {
      "type": "warning",
      "label": "Unusual termination clause",
      "description": "The termination clause allows immediate termination without notice."
    }
  ],
  "signSummary": "Standard service agreement with two signers and a 30-day deadline."
}

GET /organizations/:orgId/projects/:projectId/documents/:docId/similar

Find documents in the organization that are semantically similar to the specified document. Uses AI-generated embeddings and cosine similarity to rank results. The source document must have been analyzed first.

Authentication

Requires a valid API key or session token via the Authorization header. The requesting user must have at least the user role in the organization.

Query parameters

Parameter Type Default Description
limit integer 10 Maximum number of results to return (1–50)
threshold float 0.5 Minimum similarity score to include a result (0.0–1.0)
GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents/{docId}/similar?limit=5&threshold=0.7 \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "similarDocuments": [
    {
      "id": "d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8",
      "name": "Service Agreement 2025",
      "similarityScore": 0.87,
      "status": "completed",
      "createdAt": "2025-11-20T14:30:00Z"
    },
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "name": "Consulting Contract Q4",
      "similarityScore": 0.74,
      "status": "completed",
      "createdAt": "2025-12-01T09:15:00Z"
    }
  ]
}

No embedding?

If the source document has not been analyzed (no embedding), the endpoint returns an empty array. Use the Analyze document endpoint first to generate embeddings.

Temp Sessions

When to use

Temp sessions let you upload large PDFs (up to 50 MB) separately from the document creation request. Upload the file first, then create the document by referencing the session ID. This avoids base64-encoding large files in the create request body.

For analysis (tags, taxonomy, embeddings), use the Analyze document endpoint after creating the document.

POST /organizations/:orgId/projects/:projectId/temp-sessions

Create a temporary upload session. The session expires after 30 minutes of inactivity.

POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/temp-sessions \
  -H "Authorization: Bearer ds_your_api_key"
201 Response
{
  "sessionId": "83cf255a-32bc-4186-86e3-fee9c394e88e"
}

POST /organizations/:orgId/projects/:projectId/temp-sessions/:sessionId/upload

Upload a file to the session. Accepts PDF files directly, or convertible formats (DOCX, XLSX, PPTX, etc.) which are converted to PDF server-side. Max 50 MB.

POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/temp-sessions/{sessionId}/upload \
  -H "Authorization: Bearer ds_your_api_key" \
  -F "file=@contract.pdf"
200 Response
{
  "storageKey": "temp/83cf255a-.../document.pdf",
  "fileName": "contract.pdf",
  "fileSize": 2500000
}

Then create the document

After uploading, create the document with { "sessionId": "83cf255a-..." } instead of the document field. The PDF is moved to permanent storage automatically.

Templates

GET /organizations/:orgId/templates

List all templates in the organization.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/templates \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "templates": [
    {
      "id": "t1a2b3c4-...",
      "name": "Employment Agreement",
      "description": "Standard template for employment agreements",
      "signerCount": 2,
      "signerRoles": [
        { "index": 0, "label": "Employer", "role": "signer", "signingOrder": 1 },
        { "index": 1, "label": "Employee", "role": "signer", "signingOrder": 2 }
      ],
      "createdAt": "2026-01-15T08:00:00Z"
    }
  ]
}

GET /organizations/:orgId/templates/:templateId

Get details for a specific template including field definitions and signer roles.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/templates/{templateId} \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "template": {
    "id": "t1a2b3c4-...",
    "name": "Employment Agreement",
    "description": "Standard template for employment agreements",
    "signerCount": 2,
    "signerRoles": [
      { "index": 0, "label": "Employer", "role": "signer", "signingOrder": 1 },
      { "index": 1, "label": "Employee", "role": "signer", "signingOrder": 2 }
    ],
    "creator": {
      "type": "user",
      "name": "Richard Barkestam",
      "email": "[email]",
      "userId": "u1a2b3c4-..."
    },
    "fields": [
      {
        "id": "f1a2b3c4-...",
        "signerRoleIndex": 0,
        "fieldType": "signature",
        "pageNumber": 1,
        "xPosition": 0.1,
        "yPosition": 0.8,
        "width": 0.3,
        "height": 0.05,
        "isRequired": true
      }
    ],
    "createdAt": "2026-01-15T08:00:00Z"
  }
}

POST /organizations/:orgId/projects/:projectId/documents

Create a document from a template. Provide templateId instead of document and map the template's roles to actual participants with roleMapping.

POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/documents \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Employment Agreement — Anna Lindström",
    "templateId": "t1a2b3c4-...",
    "participants": [
      {
        "name": "Acme Corp",
        "email": "[email]",
        "role": "signer",
        "language": "en"
      },
      {
        "name": "Anna Lindström",
        "email": "[email]",
        "role": "signer",
        "language": "sv"
      }
    ],
    "roleMapping": { "0": 0, "1": 1 }
  }'

roleMapping maps the template's role index (key) to the participant's index in the participants array (value). In the example above, template role 0 maps to participant 0 and template role 1 maps to participant 1.

Contacts

POST /organizations/:orgId/contacts

Create a new contact in the organization's address book. Contacts can be global (organization-wide) or scoped to a specific project.

Parameters

Parameter Type Required Description
name string Yes Contact name (1–255 characters)
email string Yes Email address
projectId string No UUID of a project to scope the contact to. Omit for a global contact
phone string No Phone number (max 50 characters)
title string No Job title (max 255 characters)
company string No Company name (max 255 characters)
personalNumber string No Swedish personal number (12 digits, YYYYMMDDXXXX)
defaultRole string No signer or reviewer (default: signer)
defaultLanguage string No sv or en (default: sv)
defaultOtpEnabled boolean No Require OTP verification by default (default: false)
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/contacts \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Anna Lindström",
    "email": "[email]",
    "company": "Acme Corp",
    "title": "CEO",
    "defaultRole": "signer",
    "defaultLanguage": "sv"
  }'
201 Response
{
  "contact": {
    "id": "c1a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c",
    "organizationId": "a1b2c3d4-...",
    "name": "Anna Lindström",
    "email": "[email]",
    "company": "Acme Corp",
    "title": "CEO",
    "defaultRole": "signer",
    "defaultLanguage": "sv",
    "defaultOtpEnabled": false,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z"
  }
}

GET /organizations/:orgId/contacts

List contacts in the organization with pagination, search, and scope filtering.

Query parameters

Parameter Type Description
page number Page number (default: 1)
limit number Items per page (default: 50, max: 100)
q string Search by name or email
scope string Filter by scope: global, project:{projectId}, or all (default)
sort string Sort order, e.g. name:asc, createdAt:desc
GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/contacts?q=anna&scope=global \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "contacts": [
    {
      "id": "c1a2b3c4-...",
      "organizationId": "a1b2c3d4-...",
      "name": "Anna Lindström",
      "email": "[email]",
      "company": "Acme Corp",
      "defaultRole": "signer",
      "defaultLanguage": "sv",
      "defaultOtpEnabled": false,
      "createdAt": "2026-03-16T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1,
    "totalPages": 1
  }
}

GET /organizations/:orgId/contacts/:contactId

Get details for a specific contact.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/contacts/{contactId} \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "contact": {
    "id": "c1a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c",
    "organizationId": "a1b2c3d4-...",
    "name": "Anna Lindström",
    "email": "[email]",
    "phone": "+46701234567",
    "company": "Acme Corp",
    "title": "CEO",
    "defaultRole": "signer",
    "defaultLanguage": "sv",
    "defaultOtpEnabled": false,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z"
  },
  "creator": {
    "type": "api_key",
    "name": "Production API Key",
    "apiKeyId": "k1a2b3c4-..."
  }
}

PUT /organizations/:orgId/contacts/:contactId

Update an existing contact. Only the fields you include will be updated.

Parameters

Parameter Type Required Description
name string No Contact name (1–255 characters)
email string No Email address
phone string | null No Phone number. Set to null to clear
title string | null No Job title. Set to null to clear
company string | null No Company name. Set to null to clear
personalNumber string | null No Swedish personal number. Set to null to clear
defaultRole string No signer or reviewer
defaultLanguage string No sv or en
defaultOtpEnabled boolean No Require OTP verification by default
PUT Example request
curl -X PUT https://api.signeum.se/api/v1/organizations/{orgId}/contacts/{contactId} \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+46701234567",
    "title": "CTO"
  }'
200 Response
{
  "contact": {
    "id": "c1a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c",
    "organizationId": "a1b2c3d4-...",
    "name": "Anna Lindström",
    "email": "[email]",
    "phone": "+46701234567",
    "company": "Acme Corp",
    "title": "CTO",
    "defaultRole": "signer",
    "defaultLanguage": "sv",
    "defaultOtpEnabled": false,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T12:00:00Z"
  }
}

DELETE /organizations/:orgId/contacts/:contactId

Delete a contact from the address book.

DELETE Example request
curl -X DELETE https://api.signeum.se/api/v1/organizations/{orgId}/contacts/{contactId} \
  -H "Authorization: Bearer ds_your_api_key"
204 Response
No content

Webhook Endpoints

POST /organizations/:orgId/projects/:projectId/webhooks

Create a new webhook endpoint for a project. Webhook endpoints receive POST requests for document lifecycle events.

Parameters

Parameter Type Required Description
url string Yes HTTPS URL to receive webhook events (max 2048 chars)
eventTypes array Yes Event types to subscribe to, e.g. ["document.signed", "document.completed"]
description string No Human-readable description (max 255 chars)
includeFields array No Extra fields to include in the payload: tags, taxonomy, risk_flags
enabled boolean No Whether the endpoint is active (default: true)
POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/signeum",
    "eventTypes": ["document.signed", "document.completed"],
    "description": "Production webhook"
  }'
201 Response
{
  "endpoint": {
    "id": "w1a2b3c4-...",
    "projectId": "e5f6a7b8-...",
    "organizationId": "a1b2c3d4-...",
    "url": "https://your-app.com/webhooks/signeum",
    "description": "Production webhook",
    "eventTypes": ["document.signed", "document.completed"],
    "includeFields": null,
    "enabled": true,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z"
  }
}

GET /organizations/:orgId/projects/:projectId/webhooks

List all webhook endpoints configured for a project.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "endpoints": [
    {
      "id": "w1a2b3c4-...",
      "projectId": "e5f6a7b8-...",
      "url": "https://your-app.com/webhooks/signeum",
      "description": "Production webhook",
      "eventTypes": ["document.signed", "document.completed"],
      "enabled": true,
      "createdAt": "2026-03-16T10:00:00Z",
      "updatedAt": "2026-03-16T10:00:00Z"
    }
  ]
}

GET /organizations/:orgId/projects/:projectId/webhooks/:webhookId

Get details for a specific webhook endpoint.

GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks/{webhookId} \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "endpoint": {
    "id": "w1a2b3c4-...",
    "projectId": "e5f6a7b8-...",
    "organizationId": "a1b2c3d4-...",
    "url": "https://your-app.com/webhooks/signeum",
    "description": "Production webhook",
    "eventTypes": ["document.signed", "document.completed"],
    "includeFields": null,
    "enabled": true,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T10:00:00Z"
  }
}

PUT /organizations/:orgId/projects/:projectId/webhooks/:webhookId

Update an existing webhook endpoint. All fields are optional.

Parameters

Parameter Type Required Description
url string No New HTTPS URL
eventTypes array No Updated event types
description string | null No Updated description (set to null to clear)
includeFields array | null No Updated extra fields (set to null to clear)
enabled boolean No Enable or disable the endpoint
PUT Example request
curl -X PUT https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks/{webhookId} \
  -H "Authorization: Bearer ds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "eventTypes": ["document.signed", "document.completed", "document.cancelled"],
    "enabled": true
  }'
200 Response
{
  "endpoint": {
    "id": "w1a2b3c4-...",
    "projectId": "e5f6a7b8-...",
    "organizationId": "a1b2c3d4-...",
    "url": "https://your-app.com/webhooks/signeum",
    "description": "Production webhook",
    "eventTypes": ["document.signed", "document.completed", "document.cancelled"],
    "includeFields": null,
    "enabled": true,
    "createdAt": "2026-03-16T10:00:00Z",
    "updatedAt": "2026-03-16T12:00:00Z"
  }
}

DELETE /organizations/:orgId/projects/:projectId/webhooks/:webhookId

Delete a webhook endpoint.

DELETE Example request
curl -X DELETE https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks/{webhookId} \
  -H "Authorization: Bearer ds_your_api_key"
204 Response
No content

POST /organizations/:orgId/projects/:projectId/webhooks/:webhookId/test

Send a webhook.test event to the endpoint. The test event goes through the full delivery pipeline including HMAC signing, so you can verify your receiver end-to-end.

POST Example request
curl -X POST https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks/{webhookId}/test \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "success": true,
  "statusCode": 200,
  "error": null
}

GET /organizations/:orgId/projects/:projectId/webhooks/:webhookId/logs

Return paginated delivery logs for a webhook endpoint, most recent first.

Query parameters

Parameter Type Default Description
page integer 1 Page number
limit integer 20 Items per page (max 100)
GET Example request
curl https://api.signeum.se/api/v1/organizations/{orgId}/projects/{projectId}/webhooks/{webhookId}/logs?page=1&limit=10 \
  -H "Authorization: Bearer ds_your_api_key"
200 Response
{
  "logs": [
    {
      "id": "log-uuid-...",
      "webhookEndpointId": "w1a2b3c4-...",
      "eventType": "document.signed",
      "statusCode": 200,
      "success": true,
      "createdAt": "2026-03-16T10:30:00Z"
    }
  ],
  "total": 42,
  "page": 1,
  "limit": 10
}