EmployeesSubmit a timesheet period for approval

Submit a timesheet period for approval

Closes every day from StartDate to EndDate of an employee's timesheet and sends it for approval.

The API equivalent of the employee pressing "submit" on a week or month. Refused as a whole when the employee has a time tracker running on one of the days, or when the account forbids closing a period with zero hours / below standard time. Can be called for another employee by a user with the rights described below.

Use it to:

  • Auto-submit timesheets at the end of the week for employees whose hours come from another system.
  • A manager or integration user closes the month for employees before payroll.

Not for:

  • Submitting single registrations — use POST /v1/approval/timesheets/submit-time-registrations.
  • Approving or rejecting — no REST operation in this service does that.

Rules across fields:

  • R1: StartDate must not be after EndDate; otherwise the day list is empty and the call fails with 500. Not validated.

Behaviour:

  • Not idempotent.
  • Safe to retry only under a condition. Re-submitting closes nothing new but adds another dialogue entry and raises the event again (no 'already submitted' check on this path).
  • Duplicates: Not deduplicated (see safe_to_retry_detail).
  • Side effect: Every project-time and absence registration of the employee in the period gets status Closed (employee can no longer edit).
  • Side effect: An approval-dialogue entry (CloseTimeTrackingPeriod) with Comment is stored; approval context items are set to Submitted.
  • Changes are visible to the next read immediately.
  • Batch: all_or_nothing

Call first: GET /v1/approval/timesheets/get-status-by-period

Next: GET /v1/approval/timesheets/get-status-by-period

See also: POST /v1/approval/timesheets/submit-dates, POST /v1/approval/timesheets/submit-time-registrations

Not yet documented: behaviour → batch semantics; behaviour → side effects; examples (success).

curl -X POST "https://app3.timelog.com/your-account/api/v1/approval/timesheets/submit-period" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "EmployeeUserID": 123,
  "StartDate": "2024-12-25T10:00:00Z",
  "EndDate": "2024-12-25T10:00:00Z",
  "Comment": "null"
}'
"null"
POST
/v1/approval/timesheets/submit-period
POST
Base URLstring

Target server for requests. Edit to use your own host.

Bearer Token
Bearer Tokenstring
Required

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.
Content-Typestring
Required

The media type of the request body

Options: application/json
EmployeeUserIDinteger
Required

User ID of the employee whose period is submitted. Refers to UserRead.UserID. Look up valid values with GET /v1/user. - 0, negative or omitted — 400 "'Employee User ID' must be greater than '0'." - another user than the caller, without the needed rights — 500 Code 102, ErrorCode 37966.

Format: int32
StartDatestring
Required

First day of the period, inclusive. Date only — no time component. - omitted — Binds to 0001-01-01 (no validation rule); with a real EndDate the period then spans two millennia. - later than EndDate — No validation rule: the day list is empty and the engine fails → 500 Code 100. > Not yet documented: behaviour.

Format: date-time
EndDatestring
Required

Last day of the period, inclusive. Date only — no time component.

Format: date-time
Commentstringnull

Optional free text stored on the period's submit dialogue entry. Contains personal data.

Request Preview
Response

Response will appear here after sending the request

Authentication

header
Authorizationstring
Required

Bearer token. OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).

The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.

Not yet documented: how to obtain a token.

Not yet documented: token lifetime.

Body

application/json
EmployeeUserIDinteger
Required

User ID of the employee whose period is submitted.

Refers to UserRead.UserID. Look up valid values with GET /v1/user.

  • 0, negative or omitted — 400 "'Employee User ID' must be greater than '0'."

  • another user than the caller, without the needed rights — 500 Code 102, ErrorCode 37966.

StartDatestring
Required

First day of the period, inclusive.

Date only — no time component.

  • omitted — Binds to 0001-01-01 (no validation rule); with a real EndDate the period then spans two millennia.

  • later than EndDate — No validation rule: the day list is empty and the engine fails → 500 Code 100.

Not yet documented: behaviour.

EndDatestring
Required

Last day of the period, inclusive.

Date only — no time component.

Commentstring,null

Optional free text stored on the period's submit dialogue entry.

Contains personal data.

Responses

Success without content: HTTP 200 with the literal JSON body null. Literal JSON null (TafSuccessResult). Read the result back with get-status-by-period.