--- title: payroll.hours | Doing Work API description: Payroll-ready hours for one pay period (or a custom from and to): approved minutes per person by category and by day, paid minutes (everything but break), url: https://doingwork.work/docs/reference/payroll-hours/ --- # payroll.hours Payroll-ready hours for one pay period (or a custom from and to): approved minutes per person by category and by day, paid minutes (everything but break), and what still waits for approval or is still running. ready is true when nothing is waiting. Owner or office. Hours only, no pay. | | | |---|---| | Who | Agents can call this | | REST | `GET /v1/payroll/hours` | | MCP tool | `payroll_hours` | | Writes | no | | Area | [Shop](https://doingwork.work/docs/reference/#shop) | ## When to use it Payroll-ready hours for one pay period (or a custom from and to): approved minutes per person by category and by day, paid minutes (everything but break), and what still waits for approval or is still running. ready is true when nothing is waiting. ## What to tell the owner Tell them what you found in plain words. Don't read back raw fields. ## Input | Field | Type | Required | |---|---|---| | `shop_id` | string (uuid) | yes | | `date` | string (date) | no | | `offset` | integer | no | | `from` | string (date) | no | | `to` | string (date) | no | ## Example ```http GET https://doingwork.work/v1/payroll/hours?shop_id=00000000-0000-4000-8000-000000000000 ``` ## Output | Field | Type | Always there | |---|---|---| | `shop_id` | string (uuid) | yes | | `time_zone` | string | yes | | `frequency` | string | yes | | `period_start` | string (date) | yes | | `period_end` | string (date) | yes | | `ready` | boolean | yes | | `people` | array | yes | | `people[].person_id` | string (uuid) | yes | | `people[].person_name` | ['string', 'null'] | yes | | `people[].approved_minutes` | integer | yes | | `people[].paid_minutes` | integer | yes | | `people[].paid_hours` | number | yes | | `people[].by_category_minutes` | object | yes | | `people[].by_category_minutes.work` | integer | yes | | `people[].by_category_minutes.drive` | integer | yes | | `people[].by_category_minutes.shop` | integer | yes | | `people[].by_category_minutes.break` | integer | yes | | `people[].pending_count` | integer | yes | | `people[].pending_minutes` | integer | yes | | `people[].running_count` | integer | yes | | `people[].rejected_count` | integer | yes | | `people[].days` | array | yes | | `people[].days[].date` | string (date) | yes | | `people[].days[].paid_minutes` | integer | yes | | `people[].days[].break_minutes` | integer | yes | | `approved_minutes` | integer | yes | | `paid_minutes` | integer | yes | | `paid_hours` | number | yes | | `pending_count` | integer | yes | | `running_count` | integer | yes | ```json { "shop_id": "00000000-0000-4000-8000-000000000000", "time_zone": "...", "frequency": "...", "period_start": "...", "period_end": "...", "ready": true, "people": [ { "person_id": "00000000-0000-4000-8000-000000000000", "person_name": "...", "approved_minutes": 1, "paid_minutes": 1, "paid_hours": "...", "by_category_minutes": { "work": 1, "drive": 1, "shop": 1, "break": 1 }, "pending_count": 1, "pending_minutes": 1, "running_count": 1, "rejected_count": 1, "days": [ { "date": "...", "paid_minutes": 1, "break_minutes": 1 } ] } ], "approved_minutes": 1, "paid_minutes": 1, "paid_hours": "...", "pending_count": 1, "running_count": 1 } ``` ## Errors | Code | Status | What to do | |---|---|---| | `invalid_input`, `invalid_token`, `rate_limited` | | Can happen on any call. See [errors](https://doingwork.work/docs/errors/). |