> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.projectmanager.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.projectmanager.com/_mcp/server.

# Update Time Entry

PUT https://api.projectmanager.com/api/data/timesheets/{timesheetId}
Content-Type: application/json

Updates a time entry by its unique identifier.
            
A Timesheet is a collection of time entries for a particular Resource for a specific week.  Each time
entry records the number of whole minutes spent by this Resource on an activity. An activity can be a Task
in any project that Resource can access, or the activity can be an administrative task such as "Sick
Leave" or "Meetings".  When a time entry is linked to a Task, the number of minutes spent on the time entry
are recorded as time spent on the Task.  Time entries linked to an administrative tasks are grouped for
reporting but are not added to any Task within your Workspace.
            
Time entries are recorded in whole minutes.  If you specify a time entry in fractional hours, either using
the API or via the web application, the amount you specify will be converted to minutes and rounded to the
nearest neighbor using the rounding algorithm Midpoint-Away-From-Zero.
            
When a Timesheet is submitted for approval or approved, users are no longer permitted to create, update, or
delete time entries for that week.  Users with Global Admin level access can override this restriction and
continue to make changes to a Timesheet after approval.

Reference: https://developer.projectmanager.com/api-reference/timesheet/update-time-entry

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Request

### Path parameters

- `timesheetId` (string, required) — The unique identifier of the time entry to update

### Headers

- `x-integration-name` (string, optional) — The name of the calling system passed along as a header parameter

### Body (application/json)

This endpoint expects a TimesheetUpdateRequestDto.

- `hours` (double, optional, nullable) — Reported hours. If minutes is specified this property is ignored
- `minutes` (integer, optional, nullable) — Specify the time in minutes. This overrides the Hours property.
- `notes` (string, optional, nullable) — Notes
- `documentIds` (list of string, optional, nullable) — Document Ids

## Response

### 200

Success

- `error` (AstroError, optional, nullable) — If the API call failed, this will contain information about the error that occurred.
- `success` (boolean, optional) — True if the API call succeeded; false otherwise.
- `hasError` (boolean, optional) — True if the API call failed.
- `statusCode` (enum, optional) — The HTTP code of the response.
  - Allowed values: `Continue`, `SwitchingProtocols`, `Processing`, `EarlyHints`, `OK`, `Created`, `Accepted`, `NonAuthoritativeInformation`, `NoContent`, `ResetContent`, `PartialContent`, `MultiStatus`, `AlreadyReported`, `IMUsed`, `MultipleChoices`, `MovedPermanently`, `Found`, `SeeOther`, `NotModified`, `UseProxy`, `Unused`, `TemporaryRedirect`, `PermanentRedirect`, `BadRequest`, `Unauthorized`, `PaymentRequired`, `Forbidden`, `NotFound`, `MethodNotAllowed`, `NotAcceptable`, `ProxyAuthenticationRequired`, `RequestTimeout`, `Conflict`, `Gone`, `LengthRequired`, `PreconditionFailed`, `RequestEntityTooLarge`, `RequestUriTooLong`, `UnsupportedMediaType`, `RequestedRangeNotSatisfiable`, `ExpectationFailed`, `MisdirectedRequest`, `UnprocessableEntity`, `Locked`, `FailedDependency`, `UpgradeRequired`, `PreconditionRequired`, `TooManyRequests`, `RequestHeaderFieldsTooLarge`, `UnavailableForLegalReasons`, `InternalServerError`, `NotImplemented`, `BadGateway`, `ServiceUnavailable`, `GatewayTimeout`, `HttpVersionNotSupported`, `VariantAlsoNegotiates`, `InsufficientStorage`, `LoopDetected`, `NotExtended`, `NetworkAuthenticationRequired`
- `data` (TimesheetResponseDto, optional) — Time entry representation

## Types

### AstroError

Information about an error that occurred within the ProjectManager API.

- `technicalError` (string, optional, nullable) — A technical description of the error that occurred. Not suitable for display to end users.
- `additionalErrors` (list of string, optional, nullable) — If additional errors beyond the main error in `Message` occurred, they will be listed here as individual messages.
- `validationErrors` (map from string to list of string, optional, nullable) — This contains a dictionary of validation errors. The key is the name of the field
- `message` (string, optional, nullable) — A description of the error that occurred. If your application has a user interface, show this message to explain what went wrong.

### TimesheetResponseDto

Time entry representation

- `id` (string, optional) — TimesheetId
- `taskId` (string, optional, nullable) — associated task id
- `projectId` (string, optional, nullable) — associated project id
- `resourceId` (string, optional, nullable) — resource id time entry entered
- `timesheetAdminTypeId` (string, optional, nullable) — admin task id
- `date` (string, optional) — Date of time entry
- `notes` (string, optional, nullable) — Notes
- `approved` (boolean, optional) — Shows if timesheet approved
- `hours` (double, optional, nullable) — Total Hours
- `minutes` (integer, optional, nullable) — Total Minutes
- `isCopied` (boolean, optional) — Is the timesheet entry copied from another week?
- `lastUpdatedDate` (string, optional) — Is the last timesheet modified by the user
- `documents` (list of TimesheetFileResponseDto, optional) — Document Details

### TimesheetFileResponseDto

Represents a document or file attached to a timesheet day entry.

- `id` (string, optional) — The unique identifier of the document.
- `name` (string, optional) — The name of the file (including extension).
- `url` (string, optional) — The download or access URL for the file.
- `fileType` (string, optional) — The file type or extension (e.g., "pdf", "png").
- `fileTypeLabel` (string, optional) — A user-friendly label describing the file type (e.g., "PDF Document").
- `date` (string, optional, nullable) — The date and time the file was uploaded or created.
- `size` (integer, optional) — The size of the file in bytes.
- `projectId` (string, optional) — The ID of the project associated with the file.
- `projectType` (string, optional) — The type of project (e.g., "project", "admin").
- `taskId` (string, optional, nullable) — The ID of the task this file is associated with, if any.
- `newFilename` (string, optional, nullable) — A new file name for the document, if renamed.
- `canRead` (boolean, optional, nullable) — Whether other users can read the document.
- `thumbnailUrl` (string, optional, nullable) — A thumbnail URL for previewing the file (if applicable).
- `externalId` (string, optional, nullable) — An optional external provider ID (e.g., for integrations).
- `canDelete` (boolean, optional) — Indicates whether the current user has permission to delete the file.
- `isLocked` (boolean, optional) — Indicates whether the file is locked and cannot be modified.
- `type` (string, optional) — The object type identifier used by the frontend ("pm.models.Document").
- `dirty` (boolean, optional) — Indicates whether the document has unsaved changes (used by frontend only).
- `deleted` (boolean, optional) — Indicates whether the document is marked for deletion (used by frontend only).
- `isNew` (boolean, optional) — Indicates whether the document is newly added (used by frontend only).

## Examples

**Request**

```json
{}
```

**Response**

```json
{
  "error": {
    "technicalError": "string",
    "additionalErrors": [
      "string"
    ],
    "validationErrors": {},
    "message": "string"
  },
  "success": true,
  "hasError": true,
  "statusCode": "Continue",
  "data": {
    "id": "string",
    "taskId": "string",
    "projectId": "string",
    "resourceId": "string",
    "timesheetAdminTypeId": "string",
    "date": "2024-01-15T09:30:00Z",
    "notes": "string",
    "approved": true,
    "hours": 1.1,
    "minutes": 1,
    "isCopied": true,
    "lastUpdatedDate": "2024-01-15T09:30:00Z",
    "documents": [
      {
        "id": "string",
        "name": "string",
        "url": "string",
        "fileType": "string",
        "fileTypeLabel": "string",
        "date": "2024-01-15T09:30:00Z",
        "size": 1,
        "projectId": "string",
        "projectType": "string",
        "taskId": "string",
        "newFilename": "string",
        "canRead": true,
        "thumbnailUrl": "string",
        "externalId": "string",
        "canDelete": true,
        "isLocked": true,
        "type": "string",
        "dirty": true,
        "deleted": true,
        "isNew": true
      }
    ]
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.projectmanager.com/api/data/timesheets/timesheetId"

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.put(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.projectmanager.com/api/data/timesheets/timesheetId';
const options = {
  method: 'PUT',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.projectmanager.com/api/data/timesheets/timesheetId"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("PUT", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.projectmanager.com/api/data/timesheets/timesheetId")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.put("https://api.projectmanager.com/api/data/timesheets/timesheetId")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PUT', 'https://api.projectmanager.com/api/data/timesheets/timesheetId', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.projectmanager.com/api/data/timesheets/timesheetId");
var request = new RestRequest(Method.PUT);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.projectmanager.com/api/data/timesheets/timesheetId")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PUT"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```