Jobs: forms and resources
Set one job metadata property
/a/Job_setMetaVal
Replace a top-level job metadata property with a string or decoded JSON value.
When to use this endpoint
Use for a deliberately selected metadata property after reading the current job; this is a low-level setter rather than a typed business-workflow endpoint.
Use dedicated job actions for completion, assignment or invoice workflows: editing their metadata here does not invoke those workflows.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. The handler performs no additional page or role-permission check.
Job and form IDs refer to the authenticated account. Cross-account writes occur only through the stored outsourcing relationship on the routes that explicitly mirror changes.
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. |
key | String | Yes | Trimmed truthy top-level property name. Blank and string 0 are rejected; no metadata-key allowlist. |
val | String | Yes | Trimmed truthy input. Blank and string 0 are rejected. With json unset it is stored as a string; cannot remove a property or save an empty string. |
json | String | No | Defaults to 0. Loosely equal to 1 enables associative JSON decoding of val; malformed JSON is saved as null without an error. |
Example request
$result = FM_api('Job_setMetaVal', [
'id'=>'1042', 'key'=>'integration_details',
'val'=>json_encode(['external_reference'=>'EXT-1042']), 'json'=>'1',
]);
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 ID. |
{"error":"missing or invalid parameter: key"} | Trimmed key is falsey. |
{"error":"missing or invalid parameter: val"} | Trimmed val is falsey. |
{"error":"job does not exist"} | No job row is read. |
{"ok":1,"warning":"no change needed"} | Existing property loosely equals the raw trimmed input before optional JSON decoding; no write occurs. |
{"error":"Unable to save job"} | The primary database save failed. Successful-save history and subsequent follow-ups are not run. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Lookup and UPDATE require an active job. The handler checks neither assigned-user scope nor permitted metadata names.
- Compares before decoding JSON; semantically equivalent JSON is not a reliable no-change contract. Only the selected top-level key is replaced, not merged recursively.
- Existing scalar/corrupt metadata is normalized to an empty collection before the selected key is saved. There is no pagination, maximum value length or concurrency token.
Side effects
- Unchecked metadata/timestamp/edit-marker UPDATE and meetings-cache invalidation; no direct history entry.
- Does not recalculate costs/prices, queue notifications, apply completion canonicalization, update linked invoices or mirror outsourced state.
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.
CRM2
No direct canonical or legacy caller was found in CRM2’s source. Its layout-driven job editing uses a separate contract.
Related endpoints
Job_setFieldsmerges a map of named main-form answers.Job_updateCostsrefreshes cost/resource snapshots and invokes the price follow-up.