DokumentAdress
← Alla guider

Bygg eget personalgränssnitt

Samma API som widgeten använder: personalregister, personliga koder, inrapportering, kvitton, attest och aviseringar.

Utvecklare · cirka 8 minuters läsning

Vill ni bygga personalens vy själva gör ni det mot exakt samma vägar som vår widget använder. Det finns ingen genväg som bara vår widget kommer åt.

Kräver att Tid och lön ingår i abonnemanget, annars 402 feature_unavailable.

Två slags nycklar

NyckelAnvänds avTill vad
API-nyckel ds_live_…Er serverPersonalregister, schema, attest, utläsning
Personlig kod dwt_…Den anställdes enhetTid, resa, utlägg, kvitto

Den personliga koden är kortlivad och får bara den anställdes egna data. API-nyckeln ska aldrig nå webbläsaren.

1. Personalregister (er server)

Lönesystemet äger personalen — vi speglar den. Nyckeln är anställningsnumret, eftersom det är lönesystemets egen nyckel och överlever namnbyten.

POST /staff-members — upsert på external_ref i första hand, annars employee_number. Hela registret kan skickas om utan dubbletter.

{ "staff": [ { "external_ref": "emp-9", "employee_number": "1042",
               "first_name": "Anna", "last_name": "Andersson",
               "email": "anna@exempel.se", "phone": "070-1234567",
               "employment_start": "2026-01-15", "employment_rate": 0.75,
               "employment_form": "permanent", "cost_center": "1200",
               "default_wage_code": "100",
               "tenant_ref": "nordbutik-linkoping", "is_active": true } ] }

Svar 200 (allt gick igenom) eller 207 (delvis), med results[] där varje rad har created, updated eller failed.

Detta tar vi inte emot: personnummer, hemadress, bankkonto, lön, skattetabell. De behövs inte för att koppla en tidpost till rätt person, och enligt dataskyddsreglerna får de därför inte lagras här. Skickas de ändå svarar vi 422 forbidden_fields och sparar ingenting. Okända fältnamn avvisas på samma sätt, så ett stavfel upptäcks direkt.

Har ert lönesystem inget API? Skicka personalfilen i PAXml-format till POST /staff-members/import som XML. Vi läser bara fälten ovan ur den; personnummer och adresser i filen kastas.

GET /staff-members listar aktiva; ?include_inactive=true tar med avslutade. DELETE /staff-members?id=<uuid> avslutar personen och spärrar hennes koder — raden finns kvar, historiken behövs för lönen. Avslutad personal anonymiseras automatiskt efter 12 månader.

2. Personlig kod (er server)

POST /staff-sessions med personens external_ref ger tillbaka en token (dwt_…). Den koden använder er vy som Authorization: Bearer i alla anrop nedan.

3. I er vy (personlig kod)

GET /staff/me

Personuppgifter samt hennes tid- och utläggsposter med status.

GET /staff/shifts?from=…&to=…

Hennes pass, planerade timmar och om passet redan är rapporterat. Använd det för att förifylla. Returneras bara när schemaläggning är påslagen.

POST /staff/entries

Tid mot ett pass:

{ "type": "time", "shift_id": "…", "deviation_code": "overtime",
  "started_at": "08:00", "ended_at": "17:30", "break_minutes": 30 }

Tid utan pass:

{ "type": "time", "work_date": "2026-01-15", "hours": 7.5,
  "absence_code": "SJK", "note": "" }

Resa:

{ "type": "mileage", "entry_date": "2026-01-15", "distance_km": 42.5,
  "vehicle": "ABC123", "purpose": "Leverans" }

Utlägg — belopp i kronor, vat är momsen som ingår:

{ "type": "expense", "entry_date": "2026-01-15", "amount": 249.00,
  "vat": 24.90, "purpose": "Rengöringsmedel", "document_id": "kvittots id" }

Regler: datum ÅÅÅÅ-MM-DD, klockslag HH:MM, timmar 0–24, rast 0–720 minuter, körsträcka 0,1–5000 km, moms aldrig större än beloppet. Pass över midnatt hanteras.

POST /staff/receipts — kvitto i tre steg

  1. POST /staff/receipts med filename, mime_type, byte_size, checksum_sha256 → svar med upload_url
  2. PUT upload_url med filens råa bytes
  3. POST /staff/receipts med { "document_id": "…", "confirm": true }

Skicka sedan kvittots document_id med utlägget. Kvittot blir ett vanligt dokument av typen receipt och tolkas som allt annat.

Alla widget-vägar svarar även på OPTIONS och sätter CORS mot de domäner ni angett som godkända.

4. Attest och aviseringar (er server)

GET /entries?from=…&to=… — poster bär planned_hours (från passet), hours (utfallet) och deviation_code.

POST /entries — { "decisions": [ … ] }. reason krävs vid avvisning.

Webhookhändelser: staff_entry.submitted, staff_entry.approved, staff_entry.rejected. Samma post och status ger alltid samma delivery_id, så en omkörning skapar aldrig en dubblett.

Statuskedja

submitted → approved eller rejected (med orsak) → exported (levererad till lönekörning).

Vill ni inte bygga eget?

Allt ovan finns färdigt i kundinloggningen under Personal, tid & lön: lägga upp och uppdatera anställda, bjuda in dem till egen inloggning, avsluta personal, se inlästa pass, attestera tid och utlägg samt skapa och låsa löneperioder. Samma regler gäller där som i API:et, så ni kan blanda gränssnittet och egna anrop fritt.

Hur kommer den anställde in?

Rapporteringen sker alltid som en bestämd, verifierad person, och servern härleder vem det är. Det finns tre vägar:

  1. Ni bygger eget gränssnitt. Er server sköter inloggningen, kopplar rätt användare till rätt anställningsnummer, växlar API-nyckeln mot en kortlivad personbunden session med POST /staff-sessions och rapporterar i personens namn. Nyckeln får aldrig finnas i webbläsaren.
  2. Ni bäddar in vår widget. Samma sak, men vi levererar gränssnittet. En ny session begärs varje gång widgeten öppnas, och startbeviset plockas direkt ur adressfältet.
  3. Dokumentadress Tid & lön. För er utan eget system: chefen bjuder in en befintlig anställd en gång, personen bekräftar sin e-postadress, och identiteten knyts permanent till anställningsnumret. Därefter loggar hen in med engångskod och förblir inloggad på sin telefon.

Inga lösenord lagras. Sessionen är kortlivad, kan dras in av chefen och upphör automatiskt när personen avslutas. Det finns ingen permanent länk att skicka ut.

Fortsätt läsa