{"openapi":"3.1.0","info":{"title":"Finwork Attendance API","version":"2026-10","description":"Time & attendance vendors push monthly attendance per employee for a shared employer. Full guide (Hebrew): https://finwork.co.il/developers/attendance-api","contact":{"url":"https://finwork.co.il/developers/attendance-api"}},"servers":[{"url":"https://finwork.co.il/api/v1/attendance"}],"security":[{"employerKey":[]}],"paths":{"/ping":{"get":{"summary":"Verify the API key and return the employer it belongs to","responses":{"200":{"description":"Key is valid","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"employer":{"type":"object","properties":{"name":{"type":"string"}}},"provider":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"}}},"apiVersion":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/submissions":{"post":{"summary":"Submit one month of attendance for the employer of the key","parameters":[{"name":"dryRun","in":"query","required":false,"schema":{"type":"boolean"},"description":"Validate and match employees without saving anything"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"responses":{"200":{"description":"Final submission applied (or dry run result, or idempotent replay)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionResult"}}}},"202":{"description":"Draft stored — shown to the employer, not applied to payroll","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionResult"}}}},"401":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"413":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/form101":{"post":{"summary":"Send a signed Form 101 (PDF or scan) of an employee onboarded in your system","description":"The form is read into the structured Form 101 and tax is calculated by it; the employer reviews and confirms. The employee is matched by nationalId (from the request or the form) or by a learned employeeNumber — and created from the form when not found (valid ID, name, and mobile or email on the form). Max file 3MB.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiVersion","file"],"properties":{"apiVersion":{"type":"string","enum":["2026-10"]},"employee":{"type":"object","properties":{"nationalId":{"type":"string"},"employeeNumber":{"type":"string"}}},"file":{"type":"object","required":["contentBase64"],"properties":{"contentBase64":{"type":"string","format":"byte"},"mimeType":{"type":"string","enum":["application/pdf","image/jpeg","image/png","image/webp"]},"filename":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Received for an existing employee","content":{"application/json":{"schema":{"type":"object","properties":{"form101":{"type":"object","properties":{"status":{"type":"string","enum":["received","kept_as_document"]},"taxYear":{"type":"integer"},"employee":{"type":"object","properties":{"matchedBy":{"type":"string","enum":["nationalId","employeeNumber","created"]},"created":{"type":"boolean"}}},"reviewItems":{"type":"integer"}}}}}}}},"201":{"description":"Received, and the employee was created from the form"},"401":{"$ref":"#/components/responses/Error"},"413":{"$ref":"#/components/responses/Error"},"415":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/submissions/{id}":{"get":{"summary":"Status of a previous submission (same key only)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Submission status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionResult"}}}},"404":{"$ref":"#/components/responses/Error"}}}}},"components":{"securitySchemes":{"employerKey":{"type":"http","scheme":"bearer","description":"Per-employer key created in Finwork (Integrations → Time clock). Format: fwa_live_ + 32 chars."}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"messageHe":{"type":"string"}}},"errors":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}}}}},"schemas":{"Issue":{"type":"object","required":["path","code","message","messageHe"],"properties":{"path":{"type":"string","example":"employees[4].nationalId"},"code":{"type":"string","enum":["INVALID_JSON","BODY_TOO_LARGE","UNAUTHORIZED","RATE_LIMITED","UNSUPPORTED_VERSION","REQUIRED","INVALID_VALUE","OUT_OF_RANGE","OUT_OF_PERIOD","INVALID_NATIONAL_ID","MISSING_IDENTITY","DUPLICATE_EMPLOYEE","TOO_MANY_EMPLOYEES","EMPLOYER_MISMATCH","PERIOD_LOCKED","PERIOD_NOT_OPEN","SUBMISSION_CONFLICT","NOT_FOUND","UNKNOWN_FIELD","SICK_DAYS_MISMATCH","EMPLOYEE_NOT_FOUND","IDENTITY_CONFLICT","NOT_ON_PAYROLL","FILE_TOO_LARGE","UNSUPPORTED_FILE","NOT_FORM101","FORM101_UNREADABLE","FORM101_NO_EMPLOYEE","FORM101_OTHER_EMPLOYER","KEPT_MANUAL","EXTRA_HOURS_NOTED"]},"message":{"type":"string"},"messageHe":{"type":"string"}}},"Submission":{"type":"object","required":["apiVersion","submissionId","period","employees"],"properties":{"apiVersion":{"type":"string","const":"2026-10"},"submissionId":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,120}$","description":"Unique per submission. Retry = same id; correction = new id."},"period":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$","example":"2026-10"},"status":{"type":"string","enum":["final","draft"],"default":"final"},"generatedAt":{"type":"string","format":"date-time"},"source":{"type":"object","properties":{"system":{"type":"string"},"version":{"type":"string"}}},"employer":{"type":"object","properties":{"companyNumber":{"type":"string","pattern":"^\\d{9}$","description":"Israeli company/business number — rejected if it does not match the employer of the key"}}},"employees":{"type":"array","minItems":1,"maxItems":2000,"items":{"$ref":"#/components/schemas/Employee"}}}},"Employee":{"type":"object","required":["summary"],"description":"At least one of nationalId / employeeNumber is required.","properties":{"nationalId":{"type":"string","pattern":"^\\d{5,9}$","description":"Israeli ID (check digit validated). Primary match key."},"passportNumber":{"type":"string","pattern":"^[A-Za-z0-9-]{3,20}$"},"employeeNumber":{"type":"string","maxLength":30,"description":"Employee number in the clock system — learned after the first match"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string","description":"Optional. Mobile as in the clock — not used for matching; prefills onboarding when the employee has no record at the employer yet (the Form 101 link is sent there)."},"email":{"type":"string","format":"email","description":"Optional. Same purpose as phone."},"startDate":{"type":"string","format":"date","description":"Optional. Employment start date as in the clock — prefills onboarding of a new employee."},"summary":{"type":"object","properties":{"workDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Days actually worked (days). ימי עבודה בפועל"},"regularHours":{"type":"number","minimum":0,"maximum":400,"multipleOf":0.01,"description":"Regular hours (100%) (hours). שעות רגילות (100%)"},"overtime125Hours":{"type":"number","minimum":0,"maximum":200,"multipleOf":0.01,"description":"Overtime at 125% (hours). שעות נוספות 125%"},"overtime150Hours":{"type":"number","minimum":0,"maximum":200,"multipleOf":0.01,"description":"Overtime at 150% (hours). שעות נוספות 150%"},"restDayHours":{"type":"number","minimum":0,"maximum":200,"multipleOf":0.01,"description":"Hours on weekly rest day or holiday (150%) (hours). שעות במנוחה השבועית / בחג (150%)"},"overtime175Hours":{"type":"number","minimum":0,"maximum":200,"multipleOf":0.01,"description":"Overtime at 175% (hours). שעות נוספות 175%"},"overtime200Hours":{"type":"number","minimum":0,"maximum":200,"multipleOf":0.01,"description":"Overtime at 200% (hours). שעות נוספות 200%"},"nightHours":{"type":"number","minimum":0,"maximum":300,"multipleOf":0.01,"description":"Night hours (hours). שעות לילה"},"vacationDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Vacation days (days). ימי חופשה"},"sickDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Sick days (days). ימי מחלה"},"reserveDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Reserve duty days (days). ימי מילואים"},"holidayDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Paid holiday days (days). ימי חג בתשלום"},"unpaidLeaveDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Unpaid leave days (days). חופשה ללא תשלום"},"absentDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Unexcused absence days (days). היעדרות לא מוצדקת"},"travelDays":{"type":"number","minimum":0,"maximum":31,"multipleOf":0.01,"description":"Commute days (for travel allowance) (days). ימי הגעה לעבודה (לדמי נסיעה)"}},"description":"Decimal numbers, up to 2 decimals (8.5 = eight and a half). Omitted = not sent."},"absences":{"type":"array","items":{"type":"object","required":["type","from"],"properties":{"type":{"type":"string","enum":["vacation","sick","child_sick","family_sick","reserve","reserve_spouse","mourning","unpaid","maternity","work_injury","pregnancy","holiday","other"]},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"days":{"type":"number","minimum":0,"multipleOf":0.01}}}},"days":{"type":"array","maxItems":31,"items":{"type":"object","required":["date"],"properties":{"date":{"type":"string","format":"date"},"dayType":{"type":"string","enum":["workday","friday","holiday_eve","rest","holiday"]},"workedMinutes":{"type":"integer","minimum":0,"maximum":1440},"absence":{"type":"string","enum":["vacation","sick","child_sick","family_sick","reserve","reserve_spouse","mourning","unpaid","maternity","work_injury","pregnancy","holiday","other"]}}}}}},"SubmissionResult":{"type":"object","properties":{"submission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"submissionId":{"type":"string"},"period":{"type":"string"},"status":{"type":"string","enum":["received","applied","partial","rejected"]},"final":{"type":"boolean"},"receivedAt":{"type":"string","format":"date-time"},"employees":{"type":"object","properties":{"received":{"type":"integer"},"matched":{"type":"integer"},"applied":{"type":"integer"},"keptManual":{"type":"integer"},"unmatched":{"type":"integer"}}}}},"dryRun":{"type":"boolean"},"replay":{"type":"boolean"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}}}}