{
    "info": {
        "name": "TempClock API v1.3.0",
        "_postman_id": "b6f4c1de-7a52-4c0e-9d1a-5c3e0a7b1301",
        "description": "One request per documented example. Set base_url (https://<your TempClock address>/api/v1) and api_key in the environment. Requests that name a record (?id=, worker_id ...) use the ids of the demo data they were captured on: change them to ids from your own account.",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    },
    "auth": {
        "type": "bearer",
        "bearer": [
            {
                "key": "token",
                "value": "{{api_key}}",
                "type": "string"
            }
        ]
    },
    "variable": [
        {
            "key": "base_url",
            "value": "https://tempclock.com/api/v1"
        }
    ],
    "item": [
        {
            "name": "Keys",
            "item": [
                {
                    "name": "Test a key: who it belongs to, its sites, scopes, limit and expiry",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/me.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "me.php"
                            ],
                            "query": []
                        },
                        "description": "The key making the request. Scope: any key."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Workers",
            "item": [
                {
                    "name": "List active workers (a key with pay:read and charges:read sees both rates)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php?active=true&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": [
                                {
                                    "key": "active",
                                    "value": "true"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List workers, or one worker. Scope: workers:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The same list with a workers:read key: no rates",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php?active=true&limit=1",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": [
                                {
                                    "key": "active",
                                    "value": "true"
                                },
                                {
                                    "key": "limit",
                                    "value": "1"
                                }
                            ]
                        },
                        "description": "List workers, or one worker. Scope: workers:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One worker",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php?id=327",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "327"
                                }
                            ]
                        },
                        "description": "List workers, or one worker. Scope: workers:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Workers changed since a time (nightly sync)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php?updated_since=2026-01-01T00%3A00%3A00Z&limit=1",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": [
                                {
                                    "key": "updated_since",
                                    "value": "2026-01-01T00:00:00Z"
                                },
                                {
                                    "key": "limit",
                                    "value": "1"
                                }
                            ]
                        },
                        "description": "List workers, or one worker. Scope: workers:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Create a worker (Idempotency-Key makes a retry safe)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            },
                            {
                                "key": "Idempotency-Key",
                                "value": "{{$guid}}"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": []
                        },
                        "description": "Create a worker. Scope: workers:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Jordan Example\",\n    \"employee_id\": \"DOCS-77E88\",\n    \"email\": \"jordan.example@example.test\",\n    \"phone\": \"07700 900123\",\n    \"job_role\": \"Warehouse Operative\",\n    \"location_id\": 37,\n    \"department_id\": 40,\n    \"start_date\": \"2026-10-02\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Change a worker (only the fields sent change)",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/workers.php?id=409",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "workers.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "409"
                                }
                            ]
                        },
                        "description": "Change a worker. Scope: workers:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"job_role\": \"Forklift Driver\",\n    \"cost_code_id\": 69\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Lookups",
            "item": [
                {
                    "name": "List sites",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/locations.php?limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "locations.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List sites, or one site. Scope: locations:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One site (billing fields need charges:read)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/locations.php?id=37",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "locations.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "37"
                                }
                            ]
                        },
                        "description": "List sites, or one site. Scope: locations:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "List departments, including global ones",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/departments.php?limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "departments.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List departments, or one department. Scope: departments:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One department",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/departments.php?id=40",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "departments.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "40"
                                }
                            ]
                        },
                        "description": "List departments, or one department. Scope: departments:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "List cost codes",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/cost-codes.php?limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "cost-codes.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List cost codes, or one cost code. Scope: cost_codes:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One cost code",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/cost-codes.php?id=69",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "cost-codes.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "69"
                                }
                            ]
                        },
                        "description": "List cost codes, or one cost code. Scope: cost_codes:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Time",
            "item": [
                {
                    "name": "Completed shifts on one day",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?date_from=2026-09-25&date_to=2026-09-25&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "date_from",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "date_to",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One shift with its pricing block",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?id=36686&include_pricing=true",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "36686"
                                },
                                {
                                    "key": "include_pricing",
                                    "value": "true"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Shifts created or changed in the last hour (sync feed)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?updated_since=2026-10-02T05%3A33%3A35Z&entry_filter=all&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "updated_since",
                                    "value": "2026-10-02T05:33:35Z"
                                },
                                {
                                    "key": "entry_filter",
                                    "value": "all"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Shifts payroll is waiting on, with the reason",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?date_from=2026-09-19&date_to=2026-09-25&payroll_status=on_hold&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "date_from",
                                    "value": "2026-09-19"
                                },
                                {
                                    "key": "date_to",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "payroll_status",
                                    "value": "on_hold"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Open shifts (on site now) as time entries",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?entry_filter=active&location_id=37&limit=1",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "entry_filter",
                                    "value": "active"
                                },
                                {
                                    "key": "location_id",
                                    "value": "37"
                                },
                                {
                                    "key": "limit",
                                    "value": "1"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The shift just clocked, flagged api_backdated (occurred_at was in the past)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/timesheets.php?id=40785",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "timesheets.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "40785"
                                }
                            ]
                        },
                        "description": "List time entries, or one. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Clock in by employee ID, with the time it really happened",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            },
                            {
                                "key": "Idempotency-Key",
                                "value": "{{$guid}}"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/clock.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "clock.php"
                            ],
                            "query": []
                        },
                        "description": "Clock a worker in or out. Scope: clock:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"employee_id\": \"DOCS-77E88\",\n    \"action\": \"in\",\n    \"location_id\": 37,\n    \"occurred_at\": \"2026-10-02T06:19:35Z\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The same request sent again with the same Idempotency-Key: the first answer, replayed",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            },
                            {
                                "key": "Idempotency-Key",
                                "value": "{{$guid}}"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/clock.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "clock.php"
                            ],
                            "query": []
                        },
                        "description": "Clock a worker in or out. Scope: clock:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"employee_id\": \"DOCS-77E88\",\n    \"action\": \"in\",\n    \"location_id\": 37,\n    \"occurred_at\": \"2026-10-02T06:19:35Z\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Clock out (the note is added after the clock-in note)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/clock.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "clock.php"
                            ],
                            "query": []
                        },
                        "description": "Clock a worker in or out. Scope: clock:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"action\": \"out\",\n    \"notes\": \"Left by the main gate turnstile\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Clock in from outside a warning-mode geofence, with a poor GPS reading: accepted and flagged",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/clock.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "clock.php"
                            ],
                            "query": []
                        },
                        "description": "Clock a worker in or out. Scope: clock:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"action\": \"in\",\n    \"location_id\": 39,\n    \"latitude\": 52.5264,\n    \"longitude\": -1.8998,\n    \"gps_accuracy\": 150\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Clock out with coordinates",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/clock.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "clock.php"
                            ],
                            "query": []
                        },
                        "description": "Clock a worker in or out. Scope: clock:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"action\": \"out\",\n    \"latitude\": 52.4814,\n    \"longitude\": -1.8998,\n    \"gps_accuracy\": 12\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Who is on site now, by site",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/on-site-now.php?location_id=37",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "on-site-now.php"
                            ],
                            "query": [
                                {
                                    "key": "location_id",
                                    "value": "37"
                                }
                            ]
                        },
                        "description": "Who is on site right now. Scope: onsite:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Totals only, with an onsite:read key (a site board)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/on-site-now.php?include_workers=false",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "on-site-now.php"
                            ],
                            "query": [
                                {
                                    "key": "include_workers",
                                    "value": "false"
                                }
                            ]
                        },
                        "description": "Who is on site right now. Scope: onsite:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Exceptions in a week",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/exceptions.php?from=2026-09-19&to=2026-09-25&limit=3",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "exceptions.php"
                            ],
                            "query": [
                                {
                                    "key": "from",
                                    "value": "2026-09-19"
                                },
                                {
                                    "key": "to",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "limit",
                                    "value": "3"
                                }
                            ]
                        },
                        "description": "Exceptions (the Exceptions page checks). Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Client amendment requests waiting for a decision",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/amendments.php?status=pending&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "amendments.php"
                            ],
                            "query": [
                                {
                                    "key": "status",
                                    "value": "pending"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "Client amendment requests. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One amendment request",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/amendments.php?id=11",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "amendments.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "11"
                                }
                            ]
                        },
                        "description": "Client amendment requests. Scope: timesheets:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Payroll",
            "item": [
                {
                    "name": "Payroll lines for one pay week (payroll:read key: pay figures, no charges)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/payroll.php?week=2026-09-25&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "payroll.php"
                            ],
                            "query": [
                                {
                                    "key": "week",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "Payroll lines per worker per pay week. Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "With entry ids and late adjustments, charges included",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/payroll.php?week=2026-09-25&include_entries=1&adjustments=1&limit=1",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "payroll.php"
                            ],
                            "query": [
                                {
                                    "key": "week",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "include_entries",
                                    "value": "1"
                                },
                                {
                                    "key": "adjustments",
                                    "value": "1"
                                },
                                {
                                    "key": "limit",
                                    "value": "1"
                                }
                            ]
                        },
                        "description": "Payroll lines per worker per pay week. Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Is the pay week final, and what was exported?",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/pay-weeks.php?week_start=2026-09-25",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "pay-weeks.php"
                            ],
                            "query": [
                                {
                                    "key": "week_start",
                                    "value": "2026-09-25"
                                }
                            ]
                        },
                        "description": "Is the pay week final, and what was exported?. Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The current pay week and the 7 before it",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/pay-weeks.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "pay-weeks.php"
                            ],
                            "query": []
                        },
                        "description": "Is the pay week final, and what was exported?. Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Sage, Xero and payroll files made for this client",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/export-batches.php?limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "export-batches.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "Export batches (Sage, Xero, payroll files). Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One batch with the shifts it paid",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/export-batches.php?id=8",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "export-batches.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "8"
                                }
                            ]
                        },
                        "description": "Export batches (Sage, Xero, payroll files). Scope: payroll:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Charge schedule for one pay week, with VAT",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/charges.php?week_start=2026-09-25&vat=true",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "charges.php"
                            ],
                            "query": [
                                {
                                    "key": "week_start",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "vat",
                                    "value": "true"
                                }
                            ]
                        },
                        "description": "Charge schedule (what the agency bills). Scope: charges:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Rate rules",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/rate-rules.php?limit=1",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "rate-rules.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "1"
                                }
                            ]
                        },
                        "description": "Rate rules (read only). Scope: pay:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One rate rule",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/rate-rules.php?id=44",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "rate-rules.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "44"
                                }
                            ]
                        },
                        "description": "Rate rules (read only). Scope: pay:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Bookings",
            "item": [
                {
                    "name": "Bookings on one day",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php?date_from=2026-09-25&date_to=2026-09-25&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": [
                                {
                                    "key": "date_from",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "date_to",
                                    "value": "2026-09-25"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List bookings, or one booking. Scope: shifts:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One booking",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php?id=27260",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "27260"
                                }
                            ]
                        },
                        "description": "List bookings, or one booking. Scope: shifts:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Book a worker",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": []
                        },
                        "description": "Book a worker, or cancel a booking. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"location_id\": 37,\n    \"shift_date\": \"2026-10-27\",\n    \"start_time\": \"08:00\",\n    \"end_time\": \"16:00\",\n    \"break_minutes\": 30,\n    \"job_role\": \"Warehouse Operative\",\n    \"status\": \"published\",\n    \"notes\": \"Bring safety boots\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Book a worker onto the requirement",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": []
                        },
                        "description": "Book a worker, or cancel a booking. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"demand_id\": 3066,\n    \"status\": \"published\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "A second booking that overlaps: refused with codes",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": []
                        },
                        "description": "Book a worker, or cancel a booking. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"location_id\": 38,\n    \"shift_date\": \"2026-10-27\",\n    \"start_time\": \"12:00\",\n    \"end_time\": \"20:00\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 409', () => pm.response.to.have.status(409));",
                                    "pm.test('error_code', () => pm.expect(pm.response.json().error_code).to.be.a('string'));"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Cancel a booking (the client no longer needs it)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php?id=31187&action=cancel",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31187"
                                },
                                {
                                    "key": "action",
                                    "value": "cancel"
                                }
                            ]
                        },
                        "description": "Book a worker, or cancel a booking. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"status\": \"client_cancelled\",\n    \"cancel_reason\": \"Client reduced headcount\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Change the booking times",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/shifts.php?id=31187",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "shifts.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31187"
                                }
                            ]
                        },
                        "description": "Change a booking. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"start_time\": \"09:00\",\n    \"end_time\": \"17:00\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Open requirements",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/demands.php?unfilled=true&date_from=2026-10-02&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "demands.php"
                            ],
                            "query": [
                                {
                                    "key": "unfilled",
                                    "value": "true"
                                },
                                {
                                    "key": "date_from",
                                    "value": "2026-10-02"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "List requirements, or one with its bookings. Scope: shifts:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One requirement with its bookings",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/demands.php?id=3066",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "demands.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "3066"
                                }
                            ]
                        },
                        "description": "List requirements, or one with its bookings. Scope: shifts:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Create a requirement: 3 people for an early shift",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/demands.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "demands.php"
                            ],
                            "query": []
                        },
                        "description": "Create a requirement. Scope: shifts:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"location_id\": 37,\n    \"shift_date\": \"2026-10-28\",\n    \"start_time\": \"06:00\",\n    \"end_time\": \"14:00\",\n    \"headcount\": 3,\n    \"break_minutes\": 30,\n    \"job_role\": \"Picker\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Offers sent for a requirement",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/offers.php?demand_id=3066",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "offers.php"
                            ],
                            "query": [
                                {
                                    "key": "demand_id",
                                    "value": "3066"
                                }
                            ]
                        },
                        "description": "Shift offers sent to workers (read only). Scope: shifts:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One worker's rules",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/availability.php?worker_id=409",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "availability.php"
                            ],
                            "query": [
                                {
                                    "key": "worker_id",
                                    "value": "409"
                                }
                            ]
                        },
                        "description": "Availability rules, or who is free for a slot. Scope: availability:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Who is free for a slot at a site, best matches first",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/availability.php?available_from=2026-10-28T07%3A00%3A00%2B01%3A00&available_to=2026-10-28T15%3A00%3A00%2B01%3A00&location_id=37&limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "availability.php"
                            ],
                            "query": [
                                {
                                    "key": "available_from",
                                    "value": "2026-10-28T07:00:00+01:00"
                                },
                                {
                                    "key": "available_to",
                                    "value": "2026-10-28T15:00:00+01:00"
                                },
                                {
                                    "key": "location_id",
                                    "value": "37"
                                },
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "Availability rules, or who is free for a slot. Scope: availability:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Set a weekly pattern: Monday to Friday, 06:00 to 18:00",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/availability.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "availability.php"
                            ],
                            "query": []
                        },
                        "description": "Add an availability rule. Scope: availability:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"worker_id\": 409,\n    \"type\": \"weekly\",\n    \"effective_from\": \"2026-10-02\",\n    \"slots\": [\n        {\n            \"days\": \"Mon-Fri\",\n            \"start_time\": \"06:00\",\n            \"end_time\": \"18:00\"\n        }\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Retire a rule",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/availability.php?id=82",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "availability.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "82"
                                }
                            ]
                        },
                        "description": "Retire an availability rule. Scope: availability:write."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Holiday and sickness requests",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/absences.php?limit=2",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "absences.php"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "2"
                                }
                            ]
                        },
                        "description": "Holiday and sickness requests. Scope: absences:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "Webhooks",
            "item": [
                {
                    "name": "List subscriptions",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": []
                        },
                        "description": "Subscriptions, one subscription, its delivery log, or the event list. Scope: webhooks:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "One subscription with its latest deliveries",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                }
                            ]
                        },
                        "description": "Subscriptions, one subscription, its delivery log, or the event list. Scope: webhooks:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The delivery log, with payloads",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31&action=deliveries&limit=5",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                },
                                {
                                    "key": "action",
                                    "value": "deliveries"
                                },
                                {
                                    "key": "limit",
                                    "value": "5"
                                }
                            ]
                        },
                        "description": "Subscriptions, one subscription, its delivery log, or the event list. Scope: webhooks:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "The event catalogue",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?action=events",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "action",
                                    "value": "events"
                                }
                            ]
                        },
                        "description": "Subscriptions, one subscription, its delivery log, or the event list. Scope: webhooks:read."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Subscribe to payroll events (the secret is shown once)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": []
                        },
                        "description": "Create a subscription, send a test, or rotate its secret. Scope: webhooks:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"url\": \"https://hooks.example.com/tempclock\",\n    \"events\": [\n        \"pay_week.locked\",\n        \"export.created\",\n        \"timesheet.approved\"\n    ],\n    \"description\": \"Payroll system\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 201', () => pm.response.to.have.status(201));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Send a test delivery to this subscription now (here the endpoint could not be reached)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31&action=test",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                },
                                {
                                    "key": "action",
                                    "value": "test"
                                }
                            ]
                        },
                        "description": "Create a subscription, send a test, or rotate its secret. Scope: webhooks:write."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Give the subscription a new signing secret",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31&action=rotate_secret",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                },
                                {
                                    "key": "action",
                                    "value": "rotate_secret"
                                }
                            ]
                        },
                        "description": "Create a subscription, send a test, or rotate its secret. Scope: webhooks:write."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Change the events",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                }
                            ]
                        },
                        "description": "Change a subscription. Scope: webhooks:write.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"events\": [\n        \"pay_week.locked\",\n        \"pay_week.unlocked\",\n        \"export.created\",\n        \"timesheet.approved\"\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Delete a subscription",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/webhooks.php?id=31",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "webhooks.php"
                            ],
                            "query": [
                                {
                                    "key": "id",
                                    "value": "31"
                                }
                            ]
                        },
                        "description": "Delete a subscription. Scope: webhooks:write."
                    },
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "pm.test('status 200', () => pm.response.to.have.status(200));",
                                    "pm.test('has data or message', () => { const j = pm.response.json(); pm.expect(j.data !== undefined || j.message !== undefined).to.be.true; });"
                                ]
                            }
                        }
                    ]
                }
            ]
        }
    ]
}