Schweizer Lohnausweis automatisch auslesen — Schritt-für-Schritt mit der datawork.dev API
Wie man einen Scan des Schweizer Lohnausweises (ESTV Formular 11) hochlädt, Felder wie Bruttolohn, AHV-Nummer und Abzüge extrahiert — und das Ergebnis als strukturiertes JSON mit Bildausschnitten erhält.
Inhalt
Der Schweizer Lohnausweis (ESTV Formular 11) ist ein standardisiertes Dokument, das jeder Arbeitgeber jährlich ausstellen muss. HR-Abteilungen, Treuhänder und Steuerberater verarbeiten täglich grosse Mengen davon — manuelles Abtippen ist fehleranfällig und zeitaufwendig.
Mit der datawork.dev API lässt sich ein Scan oder PDF des Lohnausweises in wenigen Zeilen Code automatisch auslesen — mit allen relevanten Ziffern und Feldern, direkt als JSON.
1. Der Schweizer Lohnausweis — Felder im Überblick
Das ESTV-Formular 11 ist in Kopfbereich und nummerierte Ziffern aufgeteilt. Folgende Felder extrahieren wir in diesem Tutorial:
Kopfbereich
Ziffern (Lohnbestandteile)
2. Voraussetzungen
Sie benötigen ein kostenloses Konto auf datawork.dev. Die API kostet CHF 0.15 pro Seite — Pay-as-you-go, keine Kreditkarte für die Registrierung nötig.
- ✓ Kostenloses Konto auf datawork.dev
- ✓ Scan oder PDF des Lohnausweises (JPG, PNG oder PDF)
- ✓ curl, JavaScript (Node.js / Browser) oder Python
3. Authentifizierung
Die API verwendet JWT-Token. Der Token ist 24 Stunden gültig.
curl -X POST https://datawork.dev/api/login \
-d "username=ihre@email.ch" \
-d "password=IhrPasswort"const res = await fetch('https://datawork.dev/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'username=ihre@email.ch&password=IhrPasswort'
});
const { access_token } = await res.json();import requests
res = requests.post('https://datawork.dev/api/login', data={
'username': 'ihre@email.ch',
'password': 'IhrPasswort'
})
token = res.json()['access_token']4. Scan hochladen & Felder definieren
Der Endpunkt POST /api/extract/analyze/async nimmt den Scan als
Multipart-Upload entgegen. Mit fields definieren Sie, welche
Felder extrahiert werden sollen, und mit includeImages=true erhalten Sie zusätzlich einen Bildausschnitt pro Feld zur Verifikation.
curl -X POST https://datawork.dev/api/extract/analyze/async \
-H "Authorization: Bearer $TOKEN" \
-F "file=@lohnausweis_2024.pdf" \
-F "fields=arbeitgeber_name,arbeitnehmer_name,ahv_nummer,beschaeftigungsjahr,ziffer_1_bruttolohn,ziffer_9_ahv_iv_eo,ziffer_9_alv,ziffer_9_pensionskasse,ziffer_10_nettolohn,ziffer_13_quellensteuer" \
-F "includeImages=true"const felder = [
'arbeitgeber_name', 'arbeitnehmer_name', 'ahv_nummer', 'beschaeftigungsjahr',
'ziffer_1_bruttolohn', 'ziffer_9_ahv_iv_eo', 'ziffer_9_alv',
'ziffer_9_pensionskasse', 'ziffer_10_nettolohn', 'ziffer_13_quellensteuer'
];
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('fields', felder.join(','));
formData.append('includeImages', 'true');
const res = await fetch('https://datawork.dev/api/extract/analyze/async', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: formData
});
const { jobId } = await res.json();
console.log('Job gestartet:', jobId);FELDER = [
'arbeitgeber_name', 'arbeitnehmer_name', 'ahv_nummer', 'beschaeftigungsjahr',
'ziffer_1_bruttolohn', 'ziffer_9_ahv_iv_eo', 'ziffer_9_alv',
'ziffer_9_pensionskasse', 'ziffer_10_nettolohn', 'ziffer_13_quellensteuer'
]
with open('lohnausweis_2024.pdf', 'rb') as f:
res = requests.post(
'https://datawork.dev/api/extract/analyze/async',
headers={'Authorization': f'Bearer {token}'},
files={'file': ('lohnausweis.pdf', f, 'application/pdf')},
data={'fields': ','.join(FELDER), 'includeImages': 'true'}
)
job_id = res.json()['jobId']
print(f'Job gestartet: {job_id}')5. Ergebnis abrufen (Polling)
Die Verarbeitung läuft asynchron. Fragen Sie den Status per GET /api/extract/jobs/{jobId} ab —
sobald status === "DONE" ist das Ergebnis verfügbar.
Typischerweise dauert die Verarbeitung 3–8 Sekunden pro Seite.
async function pollResult(jobId, token, maxAttempts = 30) {
for (let i = 0; i < maxAttempts; i++) {
const res = await fetch(`https://datawork.dev/api/extract/jobs/${jobId}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await res.json();
if (data.status === 'DONE') return data;
if (data.status === 'FAILED') throw new Error(data.errorMessage);
await new Promise(r => setTimeout(r, 2000));
}
throw new Error('Timeout');
}import time
def poll_result(job_id, token, max_attempts=30):
for _ in range(max_attempts):
res = requests.get(
f'https://datawork.dev/api/extract/jobs/{job_id}',
headers={'Authorization': f'Bearer {token}'}
)
data = res.json()
if data['status'] == 'DONE': return data
if data['status'] == 'FAILED': raise Exception(data.get('errorMessage'))
time.sleep(2)
raise TimeoutError('Job nicht abgeschlossen')6. JSON-Ergebnis & Bildausschnitte
Jedes extrahierte Feld enthält: den Wert, einen Konfidenzwert (0–1), die Position im Dokument (Bounding Box, normalisiert 0–1) sowie einen Base64-Bildausschnitt zur visuellen Verifikation.
{
"jobId": "b7e1-...",
"status": "DONE",
"result": {
"documentType": "GENERIC",
"sourceFileName": "lohnausweis_2024.pdf",
"processedPages": 1,
"analyzedAt": "2024-03-01T10:23:45Z",
"fields": [
{
"key": "arbeitgeber_name",
"value": "Muster AG",
"confidence": 0.99,
"boundingBox": { "page": 1, "x": 0.05, "y": 0.06, "width": 0.35, "height": 0.04, "unit": "normalized" },
"image": "iVBORw0KGgo..."
},
{
"key": "arbeitnehmer_name",
"value": "Maria Muster",
"confidence": 0.98,
"boundingBox": { "page": 1, "x": 0.05, "y": 0.13, "width": 0.30, "height": 0.04, "unit": "normalized" },
"image": "iVBORw0KGgo..."
},
{
"key": "ahv_nummer",
"value": "756.1234.5678.90",
"confidence": 0.97,
"boundingBox": { "page": 1, "x": 0.55, "y": 0.06, "width": 0.28, "height": 0.04, "unit": "normalized" }
},
{
"key": "ziffer_1_bruttolohn",
"value": "95'400.00",
"confidence": 0.98,
"boundingBox": { "page": 1, "x": 0.70, "y": 0.28, "width": 0.22, "height": 0.04, "unit": "normalized" },
"image": "iVBORw0KGgo..."
},
{
"key": "ziffer_9_ahv_iv_eo",
"value": "5'247.00",
"confidence": 0.96,
"boundingBox": { "page": 1, "x": 0.70, "y": 0.54, "width": 0.22, "height": 0.04, "unit": "normalized" }
},
{
"key": "ziffer_10_nettolohn",
"value": "80'888.00",
"confidence": 0.98,
"boundingBox": { "page": 1, "x": 0.70, "y": 0.70, "width": 0.22, "height": 0.04, "unit": "normalized" }
}
]
}
}image enthält einen Base64-String (PNG),
direkt in einem <img src="data:image/png;base64,...">-Tag verwendbar.
Ideal um den extrahierten Wert visuell gegen das Original zu prüfen, bevor er in die Buchhaltung übernommen wird.7. Vollständiges Python-Beispiel
Alles in einem Script — Login, Upload, Polling und strukturierte Ausgabe aller Lohnausweis-Felder:
import requests
import time
BASE_URL = 'https://datawork.dev/api'
EMAIL = 'ihre@email.ch'
PASSWORD = 'IhrPasswort'
PDF_DATEI = 'lohnausweis_2024.pdf'
FELDER = [
'arbeitgeber_name', 'arbeitnehmer_name',
'ahv_nummer', 'beschaeftigungsjahr',
'ziffer_1_bruttolohn',
'ziffer_2_verpflegung',
'ziffer_9_ahv_iv_eo', 'ziffer_9_alv',
'ziffer_9_pensionskasse', 'ziffer_9_nbuv',
'ziffer_10_nettolohn',
'ziffer_13_quellensteuer',
]
# 1. Login
res = requests.post(f'{BASE_URL}/login', data={'username': EMAIL, 'password': PASSWORD})
token = res.json()['access_token']
headers = {'Authorization': f'Bearer {token}'}
print('✓ Eingeloggt')
# 2. Lohnausweis hochladen
with open(PDF_DATEI, 'rb') as f:
res = requests.post(
f'{BASE_URL}/ocr/analyze/async',
headers=headers,
files={'file': (PDF_DATEI, f, 'application/pdf')},
data={'fields': ','.join(FELDER), 'includeImages': 'true'}
)
job_id = res.json()['jobId']
print(f'✓ Job gestartet: {job_id}')
# 3. Warten bis fertig
print(' Verarbeite...')
for _ in range(30):
time.sleep(2)
res = requests.get(f'{BASE_URL}/ocr/jobs/{job_id}', headers=headers)
data = res.json()
if data['status'] == 'DONE':
print('✓ Fertig!')
break
if data['status'] == 'FAILED':
raise Exception(f"Fehler: {data.get('errorMessage')}")
else:
raise TimeoutError('Job nicht abgeschlossen')
# 4. Felder ausgeben
print()
print('=' * 55)
print(' LOHNAUSWEIS 2024 — Extrahierte Felder')
print('=' * 55)
for field in data['result']['fields']:
konfidenz = int(field.get('confidence', 0) * 100)
wert = field.get('value', '—')
key = field.get('key', '')
print(f' {key:<28} {wert:<18} {konfidenz}%')
print('=' * 55)✓ Eingeloggt
✓ Job gestartet: b7e1-...
Verarbeite...
✓ Fertig!
=======================================================
LOHNAUSWEIS 2024 — Extrahierte Felder
=======================================================
arbeitgeber_name Muster AG 99%
arbeitnehmer_name Maria Muster 98%
ahv_nummer 756.1234.5678.90 97%
beschaeftigungsjahr 2024 99%
ziffer_1_bruttolohn 95'400.00 98%
ziffer_2_verpflegung 0.00 96%
ziffer_9_ahv_iv_eo 5'247.00 96%
ziffer_9_alv 1'145.00 97%
ziffer_9_pensionskasse 8'120.00 95%
ziffer_9_nbuv 954.00 94%
ziffer_10_nettolohn 80'888.00 98%
ziffer_13_quellensteuer 0.00 99%
=======================================================Fazit
Mit der datawork.dev API lassen sich Schweizer Lohnausweise vollständig automatisch auslesen — alle Ziffern, Abzüge und Kopffelder in einem einzigen API-Call. Das Ergebnis kommt als strukturiertes JSON zurück, inkl. Konfidenzwerten und Bildausschnitten zur Verifikation.
Ideal für Treuhänder, HR-Software, ERP-Integrationen oder eigene Applikationen — und alle Daten werden ausschliesslich auf Schweizer Servern verarbeitet, konform mit dem Datenschutzgesetz (DSG).