# QES mit Mitgliedern und Freigabe-Link

Eine qualifizierte elektronische Signatur (QES) braucht ein persönliches Zertifikat. Bei uns gehört jedes Zertifikat einem **Mitglied** Ihrer Organisation – einer Person mit oder ohne Login. Externe Empfänger eines Vorgangs unterschreiben einfach (SES) oder fortgeschritten (AES); qualifiziert unterschreiben nur Mitglieder.

Dieser Guide führt vom Mitglied über das Zertifikat bis zur Unterschrift – per API, in einem Vorgang oder über einen Freigabe-Link.

## 1. Mitglied anlegen

```http
POST /v1/members
Authorization: Bearer qgw_test_…
Idempotency-Key: 5b2e…
Content-Type: application/json

{ "firstName": "Anna", "lastName": "Weber", "email": "anna.weber@example.com", "externalId": "hr-0815" }
```

Das legt eine Person ohne Login an (`loginStatus: NO_LOGIN`), etwa eine Geschäftsführerin, die nur unterschreibt. Scope `members:manage`. Mitglieder lesen Sie mit `GET /v1/members` und `GET /v1/members/{id}`.

## 2. Zertifikat bestellen

```http
POST /v1/certificates
Authorization: Bearer qgw_test_…
Idempotency-Key: 7d41…
Content-Type: application/json

{ "memberId": "0192f1b0-0000-7000-8000-00000000010f", "kind": "OTP" }
```

- `kind: OTP`: Die Person unterschreibt jedes Mal mit einem Einmalcode aus der App ihres Zertifikatsausstellers.
- `kind: AUTOMATIC`: Unterschriften ohne Code, nur mit der Einwilligung der Person zum automatischen Signieren (siehe Schritt 4).

Scope `certificates:purchase`. Die Antwort enthält `identificationUrl`: Die Person identifiziert sich einmalig über unseren Link (sie bekommt ihn auch per E-Mail). Mit einem Test-Schlüssel wird im Testmodus bestellt und nichts berechnet. Was eine Bestellung kostet, sehen Sie vorher mit `POST /v1/cost-estimates` (Guide „Kosten per API“).

Den Stand verfolgen Sie mit `GET /v1/certificates/{id}` (`lifecycleState`) oder per Webhook: `certificate.ordered`, `certificate.activated`, `certificate.credentials_invalid`, `certificate.expiring`, `certificate.state_changed` (Scope `certificates:read`).

## 3. Zugangsdaten hinterlegen und testen

- **Zertifikate mit Einmalcodes (`OTP`):** Nur die Person selbst gibt ihre Zugangsdaten ein, in ihrer eigenen Sitzung im Dashboard; über die API lassen sie sich nicht setzen (403 / 9006).
- **Automatische Zertifikate:** `PUT /v1/certificates/{id}/credentials` speichert Benutzername und PIN verschlüsselt – nur mit gültiger Einwilligung der Person. Danach prüft `POST /v1/certificates/{id}/test` die Zugangsdaten mit einer Testsignatur.
- **Testmodus:** `POST /v1/certificates/{id}/sandbox-credentials` hinterlegt die Zugangsdaten der Sandbox an einem Test-Zertifikat, ohne sie Ihnen zu zeigen.

## 4. Einwilligung zum automatischen Signieren

Automatisch – also ohne Code – darf nur unterschrieben werden, wenn die Person zugestimmt hat. `POST /v1/certificates/{id}/consent-request` schickt ihr einen persönlichen Link; sie legt fest, wofür die Einwilligung gilt (Kanäle `API`, `DASHBOARD`, `ENVELOPE`, `BATCH`, optional bestimmte Schlüssel, Vorlagen, ein Tageslimit und ein Ablaufdatum) und kann sie jederzeit widerrufen. Die API selbst erteilt nie eine Einwilligung. Änderungen melden `certificate.consent_changed`-Ereignisse.

## 5. Unterschreiben

### Einzelne Dokumente

```http
POST /v1/signatures
Authorization: Bearer qgw_test_…
Idempotency-Key: 1c9a…
Content-Type: application/json

{ "documentId": "0192f1b0-0000-7000-8000-000000000103", "certificateId": "0192f1b0-0000-7000-8000-00000000010e",
  "placement": { "page": 1, "x": 391, "y": 36, "width": 168, "height": 39 } }
```

`certificateId` wählt das Zertifikat; Ihre Systeme halten nie eine PIN. Bei `OTP`-Zertifikaten gehört der aktuelle Code als `certificateOtp` dazu – er gilt nur kurz und muss deshalb von der Person selbst kommen. Sitzt die Person nicht vor Ihrer Oberfläche, nutzen Sie den Freigabe-Link (unten). Ergebnis: `GET /v1/signatures/{id}`, Download `GET /v1/signatures/{id}/content`; mehrere Dokumente in einem Aufruf: `POST /v1/signature-batches`.

### Antwortzeit und Wiederholungen

- `POST /v1/signatures` antwortet in der Regel innerhalb von 25 Sekunden; die Vorbereitung großer Dokumente (Laden, Signaturfeld, Bild) zählt mit und wird nicht abgebrochen. Die Antwort ist: fertig mit 200 oder, wenn der Signaturdienst bis dahin nicht fertig ist, mit 202 `status: WAIT_SIGN` und `Retry-After: 2`. Die Signatur wird dann im Hintergrund fertig und nie ein zweites Mal ausgelöst; das Ergebnis kommt an Ihren `callback`, mit Webhook-Abo als `signature.completed` und über `GET /v1/signatures/{id}` (frühestens nach `Retry-After` Sekunden abfragen). Lehnt der Signaturdienst sie erst danach ab, kommt genau einmal `signature.failed` (Webhook und `callback`), `GET` zeigt `status: REJECTED` mit `error` (bei 9019 mit `error.reason`: `signature_refused`, `timestamp_failed` oder `rejected`).
- Stellen Sie das Zeitlimit Ihres Clients auf mindestens 30 Sekunden (25 Sekunden plus Puffer). Anfragen mit `certificateOtp` warten wie bisher auf den Signaturdienst (bis zu 90 Sekunden).
- Senden Sie immer einen `Idempotency-Key`. Eine Wiederholung mit demselben Schlüssel antwortet 409 / 9008, solange die Signatur noch läuft („läuft noch, kurz warten“), danach mit der fertigen Signatur (200, dieselbe `id`). Ein 202 wird nie als Antwort gespeichert; eine Wiederholung zeigt immer den aktuellen Stand.
- Der erste Aufruf nach einer längeren Ruhepause kann beim Signaturdienst länger dauern als die folgenden.
- Viele Dokumente auf einmal: `Prefer: respond-async` (sofort 202, die Signaturen laufen über die Warteschlange des Gateways) oder `POST /v1/signature-batches`.

### Sichtbares Signaturbild

Mit `placement` zeichnet der Gateway das Signaturbild selbst: Siegel, „Qualifiziert elektronisch signiert“, die Unterschrift (Name in Handschrift oder die hinterlegte Unterschrift mit `signerImage.template: "signer"`) und darunter eine Zeile je Angabe – mit `appearance.showDate: true` Datum und Uhrzeit in der Zeitzone Ihrer Organisation mit ihrem Abstand zu UTC (`05.10.2026 22:54 UTC+2`, im Winter `UTC+1`; Einstellung im Dashboard, Standard Europe/Berlin), dann `appearance.reason` (bis 120 Zeichen), bei Bedarf über mehrere Zeilen umbrochen. Die Unterschrift behält dabei mindestens 45 % der Höhe, die Schrift wird bis 5 pt verkleinert. Passt der Grund trotzdem nicht ganz, wird er im Bild mit „…“ gekürzt und die Signatur meldet `options.appearance.reasonTruncated: true` (Antwort von `POST /v1/signatures`, `GET /v1/signatures/{id}` – auch für jedes Dokument aus `POST /v1/signature-batches` –, Ereignisse); signiert wird trotzdem, und der vollständige Grund steht in der Signatur selbst. Empfohlene Mindestgrößen des Feldes (Breite × Höhe in pt, gemessen mit üblichem deutschem Text):

| Inhalt des Bildes | Name in Handschrift | Eigene Unterschrift mit Name (`showName`) |
| --- | --- | --- |
| Datum, kein Grund | 140 × 40 | 140 × 50 |
| Datum und Grund bis 40 Zeichen | 180 × 60 | 200 × 75 |
| Datum und Grund bis 120 Zeichen | 260 × 80 | 260 × 100 |

Ein Feld von 170 × 60 pt fasst Datum und etwa 40 Zeichen Grund, 140 × 40 pt nur das Datum. Kleinere Felder sind erlaubt (ab 16 × 16 pt); Datum und Name werden dann kleiner, der Grund früher gekürzt.

### In einem Vorgang

Tragen Sie das Mitglied als Empfänger mit `memberId` und `signatureLevel: "QES"` ein. Ist es an der Reihe, unterschreibt es im Dashboard (Aufgaben, `GET /v1/members/{id}/tasks` zeigt sie Ihrem System), über einen Freigabe-Link oder – bei automatischen Zertifikaten mit passender Einwilligung – per `POST /v1/envelopes/{id}/recipients/{recipientId}/sign` (Scope `envelopes:sign`, standardmäßig aus).

### Über einen Freigabe-Link

Für Mitglieder mit `OTP`-Zertifikat: `POST /v1/signing-approvals` schickt der Person einen Link auf unsere Seite, auf der sie die Liste der Dokumente prüft und je Dokument ihren Code eingibt – ohne Login. Ablauf, Zustände, Ereignisse und Fehler beschreibt der Guide „Freigabe-Links“. Freigabe-Links stehen zur Verfügung, sobald sie in Ihrer Installation freigeschaltet sind; bis dahin antworten die Routen mit 422 / 9012 `approval_not_available`.

## Hinweise

- Live-Unterschriften beachten das monatliche Ausgabenlimit Ihrer Organisation (403 / 9017 bei hartem Limit).
- `/v1/signers` ist ein abgekündigter Alias von `/v1/members` (Header `Deprecation` und `Link`); neue Integrationen nutzen `/v1/members` und `/v1/certificates`.
