Timesheet API: document create, update, and trash endpoints#376
Timesheet API: document create, update, and trash endpoints#376
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db3cf6251d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive API documentation for creating and updating timesheet entries in the Basecamp 4 API. It includes detailed endpoint specifications, parameter descriptions, JSON request/response examples, and cURL commands following the established documentation patterns.
Changes:
- Added documentation for POST endpoint to create timesheet entries with date, hours, description, and person_id parameters
- Added documentation for PUT endpoint to update existing timesheet entries
- Added link to the shared recordings trash endpoint for deleting timesheet entries
- Removed Authentication from auto-generated API endpoints list in README (intentional cleanup)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| sections/timesheets.md | Added complete documentation for creating and updating timesheet entries, including required/optional parameters, JSON examples, and cURL commands |
| README.md | Removed Authentication line from auto-generated API endpoints list (appears to be intentional cleanup) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add documentation for the new write endpoints: - POST to create timesheet entries with date, hours, description - PUT to update existing entries - Trash via the shared recordings endpoint Includes auto-generated JSON response examples.
Add the "Get a timesheet entry" show endpoint and include the person (who the time is logged for) in all timesheet entry JSON responses. Follows up on #376 which documented the write endpoints.
Add the "Get a timesheet entry" show endpoint and include the person (who the time is logged for) in all timesheet entry JSON responses. Follows up on #376 which documented the write endpoints.
|
Not sure if there is an issue with the Timesheet API or i am doing something wrong. Ive run a lot of tests on it and i think there is also a documentation error in regards to the CREATE endpoint. Please confirm you are seeing this message as i am not sure you get this after this has been closed. Basecamp Timesheet API Curl TestsBase URL: XXXXXXX - is my account ID GET Requests (All Successful)
Conclusion: All GET endpoints work. POST Requests —
|
| # | URL Path | Body | HTTP |
|---|---|---|---|
| 5 | POST /buckets/43420314/recordings/8939176616/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"API test"} |
404 |
| 6 | POST /buckets/43420314/recordings/8939314382/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"curl test from todo"} |
404 |
| 7 | POST /buckets/43420314/recordings/8939176614/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"curl test with timesheet recording"} |
404 |
| 8 | POST /buckets/43420314/recordings/8939394639/timesheet/entries.json |
{"date":"2026-02-14","hours":"1:30","description":"Client meeting prep"} |
404 |
Conclusion: /buckets/ path does not work for POST on this account. Returns HTML, not JSON.
POST Requests — /projects/ Path with Recording (All 400)
All returned {"status":400,"error":"Bad Request"} with no additional detail.
| # | URL Path | Body | HTTP |
|---|---|---|---|
| 9 | POST /projects/43420314/recordings/8939176616/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"API test"} |
404 (recording 8939176616 is a todoset, not valid) |
| 10 | POST /projects/43420314/recordings/8939176614/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"curl test projects path"} |
400 |
| 11 | POST /projects/43420314/recordings/8939176614/timesheet/entries.json |
{"date":"2026-02-15","hours":"1.0","description":"curl test"} |
400 |
| 12 | POST /projects/43420314/recordings/8939176614/timesheet/entries.json |
{"date":"2026-02-16","hours":"2"} |
400 |
| 13 | POST /projects/43420314/recordings/8939314382/timesheet/entries.json |
{"date":"2026-02-16","hours":"2"} |
400 |
| 14 | POST /projects/43420314/recordings/8939314382/timesheet/entries.json |
{"date":"2026-02-16","hours":"2","description":"test entry via API"} |
400 |
| 15 | POST /projects/43420314/recordings/8939314382/timesheet/entries.json |
{"date":"2026-02-16","hours":"1:30","description":"API test time format"} |
400 |
| 16 | POST /projects/43420314/recordings/8939394639/timesheet/entries.json |
{"date":"2026-02-14","hours":"2.0","description":"curl test entry"} |
400 |
| 17 | POST /projects/43420314/recordings/8939394639/timesheet/entries.json |
{"date":"2026-02-14","hours":"2.0","description":"test"} (different User-Agent) |
400 |
| 18 | POST /projects/43420314/recordings/8939394639/timesheet/entries.json |
{} (empty body) |
400 |
Variations tested (all 400):
- Hours formats:
"0.25","1.0","2","2.0","1:30" - With/without
description - Empty body
{} - Different User-Agent strings
- With/without Accept header
POST Requests — /projects/.../timesheet/entries.json (No Recording — All 404)
Attempted project-level timesheet entry (no recording segment). All returned HTML 404.
| # | URL Path | Body | HTTP |
|---|---|---|---|
| 19 | POST /projects/43420314/timesheet/entries.json |
{"date":"2026-02-15","hours":"0.25","description":"API test"} |
404 |
| 20 | POST /projects/43420314/timesheet/entries.json |
{"date":"2026-02-16","hours":"0.5","description":"test project level entry"} |
404 |
| 21 | POST /projects/43420314/timesheet/entries.json |
{"recording_id":8939394639,"date":"2026-02-14","hours":"2.0","description":"test with recording in body"} |
404 |
PUT Requests (Update Existing Entry — Both Failed)
Attempted to update existing entry 9501969593.
| # | URL Path | Body | HTTP | Response |
|---|---|---|---|---|
| 22 | PUT /buckets/43420314/timesheet/entries/9501969593.json |
{"description":"updated via API test"} |
404 | HTML error page |
| 23 | PUT /projects/43420314/timesheet/entries/9501969593.json |
{"description":"updated via API test"} |
400 | {"status":400,"error":"Bad Request"} |
Summary
- All reads work — OAuth token has valid read access
- All writes fail — every POST and PUT returns 400 or 404
/buckets/path: always HTML 404 (route doesn't exist on this account) - used for POST in the documentation for Timesheets/projects/path: always JSON 400{"status":400,"error":"Bad Request"}(no details) - which is not the one used for POST in the documentation for Timesheets- Tried every combination of recording IDs, hour formats, body content, headers
i have a feeling that there is some writing permission problem.
|
Confirmed @alexbudin! Updated docs with wrong paths; fixing. Thanks for reporting. |
The create and update endpoint descriptions and cURL examples incorrectly used `/buckets/` in the URL path, but the routes only exist under `/projects/`. This caused 404s for customers following the documentation. Fixes #376 (comment)
|
@jeremy BUT why do i get 400 even if i use the /projects entry endpoint? |
|
@alexbudin JSON params wrapping bug. Fixing that too! |
|
i keep testing every 30 minutes :)))) |
The create and update endpoint descriptions and cURL examples incorrectly used `/buckets/` in the URL path, but the routes only exist under `/projects/`. This caused 404s for customers following the documentation. Fixes #376 (comment)
|
@alexbudin Fix deployed. |
|
Works! Thank you so munch! |
|
@jeremy Was reading the documentation more closely and noticed that there is no mention on how to add time to the project only, without specifying a todo. is it possible to add hours directly to the project like in the platform? or a todo must be specified in the endpoint url? |
|
@alexbudin it is possible, but not discoverable: get the project timesheet from the dock first, then POST /projects/:id/recordings/:recording_id/timesheet/entries.json. I'll document and make it discoverable. |
|
@alexbudin documented here: #382 |
|
Awesome!. ill have a play a bit later today with this. |
Summary
Companion to basecamp/bc3#9590.
Test plan
./script/api/update_docs