Jobs: forms and resources
Set job duration and estimated finish
/a/Job_setHours
Change job duration in hours and refresh estimated completion for incomplete jobs.
When to use this endpoint
Use for a positive duration edit; the value is hours, not minutes. Incomplete jobs also receive a work-time-based finish estimate.
This endpoint does not mark a job complete or alter its completion status.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session; IDs are physical job IDs in the authenticated account.
The handler enforces legacy userdata.permissions bit 128 with No permission to edit and has no client-admin exemption. There is no additional assignee or department scope.
The dispatcher also applies account/user and IP restrictions. A CRM session carrying a CSRF token must supply it through X-FMCSRF or _csrf; missing/incorrect tokens can be rejected before this handler runs.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer string | Yes | Positive physical job ID. |
value | Numeric string | Yes | Duration converted by floatval and required to be greater than zero. Fractions such as 1.5 are hours; zero/blank cannot clear duration. No explicit finite/maximum bound is enforced. |
Example request
$result = FM_api('Job_setHours', ['id'=>'1042', 'value'=>'1.5']);
Example response
{"ok":1}
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"missing or invalid parameter: id"} | Nonpositive job ID. |
{"error":"no value provided"} | Converted duration is zero/negative. |
{"error":"No permission to edit"} | Edit restriction bit 128 is set. |
{"error":"job does not exist"} | No active job is read. |
{"ok":1,"warning":"value already set"} | Hours compare equal and either the job is not incomplete or its stored local/epoch finish already matches the newly calculated estimate. |
{"error":"Unable to save job"} | The primary database save failed. Successful-save history and subsequent follow-ups are not run. |
{"ok":1,"warning":"Job saved; follow-up incomplete. Inspect saved state before retrying.","warnings":["Job_updateCosts: Unable to save job"],"saved":1} | The primary save succeeded, but a recalculation, asset rebuild, notification or outsourced mirror failed. warnings identifies the failed follow-up; any normal response fields remain present. A benign no-change result from a follow-up is not a failure. Read saved state before retrying. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- For is_complete=0 only, calculates a local finish from meeting_time_e and hours, aligns date_completed/date_completed_e, and writes meta.completion_date.times-edited.timestamp while preserving other metadata.
- The work-time helper uses work-day-start/work-day-end in minutes and week-days-off (Sunday=0). It spreads long durations over working days, falling back to an eight-hour day length if configured end-start is nonpositive. It is not a holiday-calendar or general scheduling engine; short durations use the start time directly.
- Nonzero completion statuses retain their stored completion fields. Equal duration can still trigger an incomplete-job repair when the finish is stale.
- Does not persist a freshly computed minutes_worked breakdown from the cost helper; an existing value is retained. No paging or batch input is provided.
Side effects
- Checked active-job duration/finish/meta UPDATE with timestamps/edit marker, meetings-cache invalidation and job history after the save succeeds.
- Mirrors hours to an outsourced counterpart. Whether to alter its finish depends on the local job’s completion status, not the remote one. Remote local time uses its account timezone, but work-day settings come from the current account; the remote lookup and UPDATE require an active job. A missing/deleted counterpart returns a saved-state warning.
- Calls Job_updateCosts, which can update cost/resource fields and prices; failures produce saved-state warnings. No direct completion notification or assignment/schedule-notification action is invoked.
See it in Fieldmotion
CRM1
No direct canonical or legacy caller was found in CRM1’s source. This endpoint is available to integrations and internal server calls; do not infer a dedicated screen. Normal duration editing is part of the job editor rather than a direct caller of this route.
CRM2
No direct canonical or legacy caller was found in CRM2’s source. Its layout-driven job editing uses a separate contract. No dedicated Job_setHours request was found for its duration editor.
Related endpoints
Job_setMetaValwrites one low-level metadata property without typed workflow side effects.Job_updateCostsrefreshes cost/resource snapshots and invokes the price follow-up.