Für Entwickler
API-Dokumentation
Mit der Signeur REST-API kann Ihre Anwendung Signaturanfragen erstellen, deren Status überwachen und gesperrte PDFs herunterladen. Diese Dokumentation beschreibt die heute verfügbaren Endpunkte.
https://signeur.euAuthentifizierung
Alle API-Aufrufe erfordern einen Bearer-Token im Authorization-Header. Tokens werden mit SHA-256 gehasht und mit dem gespeicherten Hash verglichen — der Klartext wird nirgends persistiert.
Beispiel:
Authorization: Bearer sgn_live_xxx...Beziehen Sie einen API-Schlüssel vom Dienstadministrator. Schlüsselformat ist sgn_live_<random>.
Fehlerantworten
Alle Fehler werden als JSON mit den Feldern error und message zurückgegeben. HTTP-Statuscodes folgen den Konventionen.
{
"error": "invalid_signer_email",
"message": "Field 'signer_email' is missing or not a valid email."
}| Code | Bedeutung |
|---|---|
400 | Bad request (validointi ei mene läpi) |
401 | Authorization-otsikko puuttuu tai Bearer-token virheellinen |
404 | Resurssia ei löytynyt tai se kuuluu toiselle organisaatiolle |
409 | Konflikti: pyyntö on jo allekirjoitettu / ei vielä allekirjoitettu |
410 | Resurssi on vanhentunut (linkki yli 30 päivää vanha) |
429 | Liian monta pyyntöä — odota Retry-After-otsikon ilmoittama aika |
500 | Palvelinvirhe (DB-, Storage- tai email-välitysvirhe) |
Rate Limits
Eine Begrenzung pro Organisation ist noch nicht erzwungen. Nutzen Sie die API verantwortungsvoll — Missbrauch kann zur Widerrufung des API-Schlüssels führen. Volumenbasierte Limits werden später hinzugefügt.
Idempotenz
Alle POST-Endpunkte akzeptieren einen optionalen `Idempotency-Key`-Header (eine beliebige eindeutige Zeichenkette, typischerweise eine UUID). Wenn Sie eine Anfrage mit demselben Schlüssel erneut senden, spielt Signeur die ursprüngliche Antwort ab, anstatt ein Duplikat zu erstellen. Schlüssel sind organisationsbezogen und werden 24 Stunden aufbewahrt.
POST /api/v1/signatures
Authorization: Bearer sgn_live_...
Idempotency-Key: 0d8a2c41-7e3f-4b9d-bc59-2c5fd8a91f4d
Content-Type: application/json
{ … }Wenn Sie denselben Schlüssel mit einem anderen Request-Body senden, gibt Signeur 409 idempotency_key_conflict zurück. Wiedergegebene Antworten enthalten den Header `Idempotent-Replayed: true` zur clientseitigen Erkennung.
Endpunkte
Signaturanfrage erstellen
Erstellt eine neue Signaturanfrage (1–20 Unterzeichner), speichert das PDF im Storage und sendet eine Einladungs-E-Mail an jeden Unterzeichner.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
title | string | ja | Titel der Anfrage (erscheint in der Einladungs-E-Mail). |
message | string | nein | Optionale Nachricht, die jedem Unterzeichner angezeigt wird. |
signers[] | array | ja | Array aus 1–20 Unterzeichner-Objekten. Mindestens eines ist erforderlich. |
signers[].email | string | ja | E-Mail-Adresse des Unterzeichners. |
signers[].name | string | nein | Name des Unterzeichners (erscheint auf der Audit-Seite). |
signers[].locale | string | nein | E-Mail-Locale pro Unterzeichner: 'en' | 'fi' | 'fr' | 'de'. Fallback zur Top-Level-Locale, dann 'en'. |
locale | string | nein | Standard-Locale für Unterzeichner, die keine eigene angeben. Erlaubte Werte: 'en' | 'fi' | 'fr' | 'de'. |
document.filename | string | ja | Ursprünglicher Dateiname des PDFs. |
document.content_base64 | string | ja | PDF-Inhalt als Base64-codierter String (max. 10 MB decodiert). |
metadata | object | nein | Freies Schlüssel-Wert-Objekt, das wörtlich an der Anfrage gespeichert wird. |
Abwärtskompatibilität: Der ältere Single-Signer-Body { "signer_email", "signer_name" } wird weiterhin akzeptiert und als einelementiges signers-Array behandelt. Neue Integrationen sollten das signers[]-Array verwenden.
Request-Body
curl -X POST https://signeur.eu/api/v1/signatures \
-H "Authorization: Bearer sgn_live_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Order Agreement #1234",
"message": "Please review and sign.",
"locale": "en",
"signers": [
{ "email": "buyer@example.com", "name": "Anna Buyer" },
{ "email": "seller@example.com", "name": "Bob Seller", "locale": "fi" }
],
"document": {
"filename": "contract.pdf",
"content_base64": "JVBERi0xLjQK..."
},
"metadata": { "deal_id": "D-42" }
}'Antwort
{
"id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"status": "sent",
"expires_at": "2026-06-13T10:51:51.813+00:00",
"signers": [
{
"id": "9c0aa5ec-…",
"email": "buyer@example.com",
"name": "Anna Buyer",
"access_token": "29ErQSUr8Ov…",
"sign_url": "https://signeur.eu/sign/29ErQSUr8Ov…",
"email_sent": true,
"email_error": null,
"locale": "en"
},
{
"id": "f12d8b3c-…",
"email": "seller@example.com",
"name": "Bob Seller",
"access_token": "kpqDAuVy9-…",
"sign_url": "https://signeur.eu/sign/kpqDAuVy9-…",
"email_sent": true,
"email_error": null,
"locale": "fi"
}
]
}Status der Signaturanfrage abrufen
Gibt den aktuellen Zustand der Anfrage, das vollständige Unterzeichner-Array und den Audit-Trail zurück. Zum Status-Polling verwenden.
Request-Body
curl https://signeur.eu/api/v1/signatures/<id> \
-H "Authorization: Bearer sgn_live_..."Antwort
{
"id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"status": "signed",
"title": "Order Agreement #1234",
"created_at": "2026-05-14T10:51:51.813Z",
"sent_at": "2026-05-14T10:51:52.012Z",
"signed_at": "2026-05-14T10:52:24.374Z",
"cancelled_at": null,
"expires_at": "2026-06-13T10:51:51.813Z",
"is_expired": false,
"signers": [
{
"id": "9c0aa5ec-…",
"email": "buyer@example.com",
"name": "Anna Buyer",
"access_token": "29ErQSUr8Ov…",
"sign_url": "https://signeur.eu/sign/29ErQSUr8Ov…",
"status": "signed",
"sent_at": "2026-05-14T10:51:52.012Z",
"opened_at": "2026-05-14T10:52:00.481Z",
"signed_at": "2026-05-14T10:52:24.374Z",
"declined_at": null,
"decline_reason": null,
"locale": "en"
}
],
"document_hash": "e5132c2fe36dfa219ec600b009d16ef38d20bf0849f7b01ba5ca6e22fec63b56",
"audit_trail": { "events": [ … ] },
"metadata": { "deal_id": "D-42" }
}Signiertes PDF herunterladen
Gibt das gesperrte PDF als Binär zurück. Gibt 409 zurück, wenn die Anfrage noch nicht signiert ist.
Request-Body
curl https://signeur.eu/api/v1/signatures/<id>/document \
-H "Authorization: Bearer sgn_live_..." \
-o signed.pdfContent-Type: application/pdf
Signaturanfragen auflisten
Gibt eine paginierte Liste der Anfragen der Organisation mit optionalen Filtern zurück.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
status | query | nein | Nach Status filtern: pending | sent | opened | signed | cancelled | declined | expired | awaiting_stamp | stamp_failed. |
created_from | query | nein | Nur Anfragen zurückgeben, die am oder nach diesem ISO-8601-Zeitstempel erstellt wurden. |
created_to | query | nein | Nur Anfragen zurückgeben, die vor diesem ISO-8601-Zeitstempel erstellt wurden. |
limit | query | nein | Seitengröße, 1–100. Standard 25. |
cursor | query | nein | Opaker Cursor aus dem next_cursor der vorherigen Antwort. Erstellen Sie keinen eigenen. |
Request-Body
curl "https://signeur.eu/api/v1/signatures?status=sent&limit=10" \
-H "Authorization: Bearer sgn_live_..."Antwort
{
"data": [
{
"id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"status": "sent",
"title": "Order Agreement #1234",
"signer_count": 2,
"created_at": "2026-05-14T10:51:51.813Z",
"sent_at": "2026-05-14T10:51:52.012Z",
"signed_at": null,
"cancelled_at": null,
"expires_at": "2026-06-13T10:51:51.813Z",
"is_expired": false
}
],
"has_more": true,
"next_cursor": "eyJjIjoiMjAyNi0wNS0xNFQxMDo1MTo1MS44MTNaIiwiaSI6IjZkYzE4OTExLi4uIn0"
}Signaturanfrage stornieren
Storniert eine ausstehende Anfrage, invalidiert alle verbleibenden Unterzeichner-Links und löst den signature_request.cancelled-Webhook aus.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
reason | string | nein | Optionaler Grund, gespeichert im Audit-Trail (max. 500 Zeichen). |
Request-Body
curl -X POST https://signeur.eu/api/v1/signatures/<id>/cancel \
-H "Authorization: Bearer sgn_live_..." \
-H "Content-Type: application/json" \
-d '{ "reason": "Sent to wrong recipient" }'Antwort
{
"id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"status": "cancelled",
"cancelled_at": "2026-05-17T08:14:02.913Z"
}Wirkung: Status wird 'cancelled', alle unsignierten Unterzeichner-Links werden invalidiert und der signature_request.cancelled-Webhook wird ausgelöst. Das Original-PDF wird aufbewahrt, ist aber über /document nicht mehr herunterladbar.
Unterzeichner einer Anfrage auflisten
Gibt alle Unterzeichner einer Signaturanfrage mit Status, Zeitstempeln und Audit-Trail zurück. Für das Rendern von Multi-Signer-Fortschrittsanzeigen.
Request-Body
curl "https://signeur.eu/api/v1/signatures/<id>/signers" \
-H "Authorization: Bearer sgn_live_..."Antwort
{
"data": [
{
"id": "9c0aa5ec-…",
"email": "buyer@example.com",
"name": "Anna Buyer",
"name_as_invited": "Anna Buyer",
"name_as_signed": "Anna H. Buyer",
"access_token": "29ErQSUr8Ov…",
"sign_url": "https://signeur.eu/sign/29ErQSUr8Ov…",
"status": "signed",
"position": 0,
"sent_at": "2026-05-14T10:51:52.012Z",
"opened_at": "2026-05-14T10:52:00.481Z",
"signed_at": "2026-05-14T10:52:24.374Z",
"declined_at": null,
"decline_reason": null,
"invalidated_at": null,
"ip_address": "87.92.91.57",
"user_agent": "Mozilla/5.0 (Macintosh; …) Safari/605.1.15",
"locale": "en",
"representing_as_invited": null,
"representing_as_signed": null,
"representing_role": null,
"representing_entity_id": null,
"audit_trail": { "events": [ … ] }
},
{
"id": "f12d8b3c-…",
"email": "seller@example.com",
"status": "pending",
"position": 1,
"...": "..."
}
]
}Einladung an einen Unterzeichner erneut senden
Sendet die Einladungs-E-Mail an einen Unterzeichner erneut mit einem frisch rotierten Zugangscode. Der alte Code funktioniert sofort nicht mehr.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
locale | string | nein | Optional. Überschreibt die E-Mail-Locale des Unterzeichners für diesen Versand und persistiert die Änderung in der Unterzeichner-Zeile. Erlaubt: 'en' | 'fi' | 'fr' | 'de'. |
Request-Body
curl -X POST https://signeur.eu/api/v1/signatures/<id>/signers/<signer_id>/resend \
-H "Authorization: Bearer sgn_live_..." \
-H "Content-Type: application/json" \
-d '{ "locale": "fi" }'Antwort
{
"ok": true,
"signer_id": "9c0aa5ec-…",
"email_sent": true,
"email_error": null,
"access_code_rotated_at": "2026-05-17T10:14:33.872Z"
}Wirkung: Ein neuer 6-stelliger Zugangscode wird generiert, als bcrypt-Hash gespeichert und per E-Mail an den Unterzeichner gesendet. Der zuvor gesendete Code authentifiziert das Access-Code-Gate nicht mehr. Versuchszähler und temporäre Sperren werden zurückgesetzt.
Audit-Trail-PDF herunterladen
Gibt ein eigenständiges PDF mit dem vollständigen Audit-Datensatz zurück: Anfrage-Metadaten, Unterzeichner-Details mit IPs und User Agents, chronologische Ereignis-Timeline und PAdES-Signatur-Informationen, wenn die Anfrage versiegelt ist. Dieses PDF ist informativ und NICHT kryptografisch signiert — das versiegelte Dokument selbst ist der rechtliche Nachweis.
Request-Body
curl https://signeur.eu/api/v1/signatures/<id>/audit-trail.pdf \
-H "Authorization: Bearer sgn_live_..." \
-o audit-trail.pdfContent-Type: application/pdf · Das PDF wird bei Bedarf aus dem aktuellen Zustand der Anfrage und des Audit-Trails generiert. Unabhängig vom Anfragestatus verfügbar.
Webhook-Endpunkte auflisten
Gibt alle für Ihre Organisation konfigurierten Webhook-Endpunkte zurück. Secrets sind in der Auflistung nicht enthalten — sie werden nur einmal bei der Erstellung angezeigt.
Request-Body
curl https://signeur.eu/api/v1/webhook-endpoints \
-H "Authorization: Bearer sgn_live_..."Antwort
{
"data": [
{
"id": "ep_a1b2c3d4-…",
"url": "https://example.com/hooks/signeur",
"event_types": ["signature_request.completed", "signer.signed"],
"description": "Production sync",
"disabled_at": null,
"created_at": "2026-05-17T10:00:00.000Z",
"updated_at": "2026-05-17T10:00:00.000Z"
}
]
}Webhook-Endpunkt erstellen
Registriert eine neue URL zum Empfangen von Webhook-Ereignissen. Die Antwort enthält ein neu generiertes `secret`, das nur dieses eine Mal angezeigt wird und zur Verifizierung von HMAC-Signaturen eingehender Webhooks dient.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
url | string | ja | Ziel-URL (muss in Produktion https:// verwenden, http://localhost ist für die Entwicklung erlaubt). |
event_types | string[] | nein | Array der zu empfangenden Ereignistypen. Leeres Array (oder weggelassen) bedeutet, alle Ereignisse empfangen. |
description | string | nein | Optionale kurze, menschenlesbare Bezeichnung für den Endpunkt (max. 200 Zeichen). |
Request-Body
curl -X POST https://signeur.eu/api/v1/webhook-endpoints \
-H "Authorization: Bearer sgn_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/signeur",
"event_types": ["signature_request.completed", "signer.signed"],
"description": "Production sync"
}'Antwort
{
"id": "ep_a1b2c3d4-…",
"url": "https://example.com/hooks/signeur",
"secret": "whsec_7f3a9c…",
"event_types": ["signature_request.completed", "signer.signed"],
"description": "Production sync",
"disabled_at": null,
"created_at": "2026-05-17T10:00:00.000Z",
"updated_at": "2026-05-17T10:00:00.000Z"
}Wichtig: Das Secret wird NUR in dieser Antwort angezeigt. Signeur behält keine Klartext-Kopie. Wenn Sie es verlieren, löschen Sie diesen Endpunkt und erstellen Sie einen neuen.
Webhook-Endpunkt aktualisieren
Aktualisiert URL, event_types, description oder disabled-Status eines Endpunkts. Alle Body-Felder sind optional — nur die angegebenen werden geändert.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
url | string | nein | Ziel-URL (muss in Produktion https:// verwenden, http://localhost ist für die Entwicklung erlaubt). |
event_types | string[] | nein | Array der zu empfangenden Ereignistypen. Leeres Array (oder weggelassen) bedeutet, alle Ereignisse empfangen. |
description | string | nein | Optionale kurze, menschenlesbare Bezeichnung für den Endpunkt (max. 200 Zeichen). |
disabled | boolean | nein | true = Zustellung pausieren ohne den Endpunkt zu löschen, false = fortsetzen. |
Webhook-Endpunkt löschen
Entfernt den Endpunkt dauerhaft. Die Zustellung von Ereignissen stoppt sofort. Das Secret ist nach dem Löschen nicht wiederherstellbar.
curl -X DELETE https://signeur.eu/api/v1/webhook-endpoints/<id> \
-H "Authorization: Bearer sgn_live_..."Webhooks
Signeur sendet Echtzeit-Ereignisse an eine oder mehrere für Ihre Organisation konfigurierte URLs, wenn sich der Status einer Signaturanfrage ändert. Jedes Ereignis wird mit HMAC-SHA256 signiert und parallel an alle passenden Endpunkte zugestellt. Dies ist effizienter als das Pollen des GET-Endpunkts.
Unterstützte Ereignisse
signature_request.created | Eine neue Signaturanfrage wurde erstellt. Wird einmal pro Anfrage ausgelöst, enthält die vollständige Unterzeichnerliste. |
signature_request.sent | Der Einladungs-E-Mail-Batch wurde für alle Unterzeichner versucht. Enthält pro Unterzeichner den email_sent-Status. |
signature_request.opened | Ein Unterzeichner hat den Link zum ersten Mal geöffnet. Wird einmal pro Anfrage ausgelöst, wenn der erste Unterzeichner sie öffnet. |
signer.signed | Ein Unterzeichner hat sein OTP erfolgreich verifiziert und unterschrieben. Wird N-mal bei einer N-Unterzeichner-Anfrage ausgelöst. |
signature_request.completed | Alle Unterzeichner haben unterzeichnet und das Dokument ist versiegelt. Enthält document_hash und download_url. |
signature_request.signed | Veralteter Alias für signature_request.completed — wird zum gleichen Zeitpunkt ausgelöst. Verwenden Sie signature_request.completed für neue Integrationen. |
signature_request.declined | Ein Unterzeichner hat abgelehnt; die Anfrage wurde in den Status 'declined' verschoben und die übrigen Unterzeichner wurden invalidiert. |
signature_request.cancelled | Die Anfrage wurde über das Dashboard oder POST /signatures/{id}/cancel storniert. |
signature_request.expired | Die Anfrage hat expires_at erreicht, bevor alle Unterzeichner unterschrieben haben. Wird einmal pro Anfrage gesendet, wenn der tägliche Expire-Cron den Status auf 'expired' setzt. |
Payload-Format
// signer.signed — fires once per signer that finishes signing
{
"id": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "signer.signed",
"created_at": "2026-05-14T10:52:24.374Z",
"data": {
"signature_request_id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"signer_id": "9c0aa5ec-…",
"signer_email": "buyer@example.com",
"signer_name": "Anna Buyer",
"signed_at": "2026-05-14T10:52:24.374Z",
"remaining_pending_signers": 1
}
}
// signature_request.completed — fires once when all signers are done
// and the PDF is sealed. signature_request.signed is a deprecated alias
// that fires at the same moment with the same payload.
{
"id": "evt_b2c3d4e5-f6a7-8901-bcde-f23456789012",
"type": "signature_request.completed",
"created_at": "2026-05-14T10:55:11.812Z",
"data": {
"signature_request_id": "6dc18911-f66b-43d6-9810-8de0b07bab04",
"status": "signed",
"signed_at": "2026-05-14T10:55:11.812Z",
"document_hash": "e5132c2fe36dfa…",
"download_url": "https://signeur.eu/api/v1/signatures/6dc18911-…/document"
}
}Signaturprüfung
Jeder Webhook wird mit HMAC-SHA256 im Header X-Signeur-Signature signiert. Verifizieren Sie ihn, um sicherzustellen, dass die Anfrage tatsächlich von Signeur stammt.
Header-Format:
X-Signeur-Signature: t=1747212744,v1=abc123def456...Signierte Daten:
<timestamp>.<raw json body>Verifizierungsbeispiel (Node.js):
import { createHmac } from "crypto";
// Verify webhook signature
const sig = req.headers["x-signeur-signature"];
const [t, v1] = sig.split(",").map(s => s.split("=")[1]);
const expected = createHmac("sha256", YOUR_WEBHOOK_SECRET)
.update(`${t}.${rawBody}`).digest("hex");
if (v1 !== expected) throw new Error("Invalid signature");Konfiguration
Endpunkte können auf zwei Arten konfiguriert werden: (a) Dashboard → Webhooks bietet eine UI zum Hinzufügen, Bearbeiten, Pausieren oder Löschen von Endpunkten und zur Auswahl der Ereignistypen pro Endpunkt. (b) Die REST-API /api/v1/webhook-endpoints ermöglicht die programmatische Verwaltung. Jeder Endpunkt erhält sein eigenes HMAC-Secret, das nur bei der Erstellung angezeigt wird — bewahren Sie es sicher auf. Ein veralteter Single-URL-Webhook auf der Organisation wird weiterhin als Fallback berücksichtigt, wenn in der neuen Tabelle keine Einträge existieren.
Zustellung
Wenn ein Ereignis ausgelöst wird, sucht Signeur alle aktiven Endpunkte, die diesen Ereignistyp abonnieren, und liefert die Payload parallel aus (5 Sekunden Timeout pro Endpunkt). Jeder Versuch wird separat im Audit-Trail der Signaturanfrage mit der Endpunkt-ID, dem HTTP-Status und einem etwaigen Fehler protokolliert. Eine Retry-Queue steht auf der Roadmap.
Bald verfügbar
Folgende Funktionen sind geplant:
- → Automatische Ablauferkennung, die signature_request.expired auslöst (derzeit bleibt der Status 'sent'/'opened' auch nach expires_at)
- → Webhook-Retry-Queue — aktuell ist jede Zustellung ein einzelner Versuch; fehlgeschlagene Ereignisse werden nicht erneut versucht
- → Idempotency-Key-Unterstützung für cancel- und resend-Endpunkte (derzeit nur POST /signatures)
- → Webhook-Zustellungshistorie im Dashboard