DISCLAIMER FIRST
Use at your own risk. This code is NOT PORTABLE, which means Microsoft is not obliged to inform you that something changed within their internal webservices.
Working Solution
Trying to use the same webservice which is used by PWA Timesheet Control
The problem is that it is undocumented.
We can call TimeSheetSendGridUpdatesForSave Action on /pwa/_vti_bin/PSI/ProjectServer.svc
.
How?
First, you have to authenticate against PSI outside of standard dll.
Problem described and solved by mylself HERE
Then you need to call the webservice with data.
For example we will use this request, which changes actual hours on my task to 12h. Following snippet is copied from Chrome DevTools -> 'Network' Tab when you change hours and click save on a actual PWA Timesheet client (in browser at http://servername/pwa/Timesheet.aspx?tsUID=06b92bf0-806e-44d5-8c94-616c50471920
)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<TimeSheetSendGridUpdatesForSave
xmlns="http://schemas.microsoft.com/office/project/server/webservices/PWA/">
<jobUid>{ba875aee-a59f-4c8f-974e-cd5f21dff7b6}</jobUid>
<tsUid>{06b92bf0-806e-44d5-8c94-616c50471920}</tsUid>
<changesJson>[
{
"updates": [
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2a",
"newProp": { "dataValue": "720000", "hasDataValue": true }
},
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2t",
"newProp": { "dataValue": "720000", "hasDataValue": true }
}
],
"changeNumber": 20
}
]
</changesJson>
<viewOptionsJson>{"dateFormat":3,"workFormat":2,"durationFormat":7,"filterType":5,"loadViewProperties":false,"newTasks":[],"importTasks":[],"removedLines":[]}</viewOptionsJson>
</TimeSheetSendGridUpdatesForSave>
</soap:Body>
</soap:Envelope>
In SOAP UI in the Auth Tab you have to supply you credentials as a user which owns the timesheet. You cannot just make a request from admin account because PSI will return
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Server</faultcode>
<faultstring xml:lang="pl-PL">ProjectServerError(s) LastError=GeneralInvalidOperation Instructions: Pass this into PSClientError constructor to access all error information</faultstring>
<detail>
<errinfo>
<general>
<class name="Nie można wprowadzić zmian w grafiku. Grafik nie został przesłany lub został odwołany.">
<error id="20011" name="GeneralInvalidOperation" uid="36ec16f4-db82-4fee-8922-2cd8d4084829"/>
</class>
</general>
</errinfo>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
That just works as on the gif below

Update 27.08.2019
Code for a call:
[TestMethod]
public void SampleChangeHoursInPlainDotNetWebClient()
{
var httpClient = new WebClient();
httpClient.UseDefaultCredentials = true; // you have to be in a timesheets user scope (windows auth, ntlm)
httpClient.Headers.Add("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
httpClient.Headers.Add("Content-Type", "text/xml; charset=UTF-8");
httpClient.Headers.Add("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
httpClient.Headers.Add("Accept-Encoding", "gzip, deflate");
httpClient.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
httpClient.Headers.Add("AsmxRoutedCall", "true");
httpClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>";
var response = httpClient.UploadString("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc", "POST", data);
}
Using RestSharp:
[TestMethod]
public void SampleChangeHours()
{
var client = new RestClient("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
client.Authenticator = new NtlmAuthenticator(new NetworkCredential("test1","Start123!@#","CORPNET"));
request.AddHeader("Host", "preprod2010");
request.AddHeader("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
request.AddHeader("Connection", "keep-alive");
request.AddHeader("Content-Type", "text/xml; charset=UTF-8");
request.AddHeader("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
request.AddHeader("Accept-Encoding", "gzip, deflate");
request.AddHeader("X-FORMS_BASED_AUTH_ACCEPTED", "f");
request.AddHeader("AsmxRoutedCall", "true");
request.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
request.AddParameter("undefined", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
}