When to use this endpoint

Use once the recipient account has finished its outsourced copy and is ready to return work to the creator. This is a one-way handoff of selected saved fields, not a merge-conflict resolver or a full job clone.

Authentication and permissions

Requires authenticated tenant context through signed API-key or CRM session. Resolves outsourcing metadata from the local job and uses that stored original tenant/job pair for cross-account access.

No extra admin/ownership check or outsource-return-mode setting guard is implemented in this handler. Dispatcher user/account/IP restrictions and session CSRF apply.

The dispatcher also applies user/account and IP restrictions. CRM sessions carrying a CSRF token must supply X-FMCSRF or _csrf; missing or incorrect tokens can be rejected before the handler runs.

Parameters

ParameterTypeRequiredDescription
idInteger stringYesPositive physical outsourced-copy job ID in the authenticated tenant. No caller-supplied destination tenant/job ID is required.

Example request

$result = FM_api('Job_returnToOutsourcer', [
	'id' => '1042',
]);

Example response

{"ok":1}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error":"no ID provided"}Missing/nonpositive id.
{"error":"not an outsourced job"}Job_isOutsourced returned false, including ordinary missing/deleted jobs.
{"error":"job does not appear to be an outsourced one"}The local row has no outsourcing metadata (for example an original rather than a copy).
{"error":"job already returned to outsourcer"}The returned property already exists, even if its value is blank/false.
{"error":"Unable to save job delivery changes"}A checked database write, audit or transaction failed; local transactional writes roll back. Cross-tenant files/commits are not distributed-atomic.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • Resolves the original only from the active copy’s persisted meta.outsourcing.link_from and id. Caller-supplied preloaded job shortcuts are not used; missing/deleted original jobs are rejected.
  • Replaces original form_values, subform_values and notes wholesale with the copy’s stored JSON/text. Only statusOnRoute and statusInProgress are copied from local metadata into original metadata; other metadata and costs/resources/accommodation are not copied.
  • Recursively inspects decoded main/table answers and nested JSON strings for safe image src filenames (JPEG, PNG, GIF, WebP or HEIC), deduplicates them and copies missing/newer bytes before changing the original.
  • File metadata uses tenant-relative images/ paths. Source queries route through the copy’s tenant, destination queries through the original tenant; file storage uses the full destination tenant path and checks success.
  • After the return transaction commits, a completed copy (is_complete=1) triggers original-job completion if ONCOMPLETE is configured, using the local acting user ID. An empty response queues the existing global retry record; uncertainty/failure is reported as a saved-success warning, not a reason to repeat the return.
  • Does not set original completion fields directly. The local returned marker is committed only after checked original/image persistence, before the external completion follow-up. Noncomplete copies can also be returned.
  • A failed original lookup, image read/storage or original database write leaves the copy unreturned. A failure to save the local marker after a cross-tenant original commit reports original_updated=1 and asks for inspection of both jobs.
  • No list filtering, paging or optimistic last_edited conflict check applies. Local calls serialize on the copy and destination writes lock the original. Different-tenant database commits and file storage are not a distributed transaction.

Side effects

  • Attempts tenant image reads/writes, replaces original answers/notes/selected metadata and advances original last_edited/edited_uuid=Job_returnToOutsourcer.
  • May call on-complete or enqueue a global retry record. Writes local meta.outsourcing.returned={cdate:Unix seconds,uid:acting user ID}, advances local edit/sync metadata and invalidates job caches. No explicit return-history entry is written.

See it in Fieldmotion

CRM1

On an outsourced copy’s job screen, Return job to Outsourcer is shown when outsource-return-mode is nonzero and not returned. The confirmation requires typing I am sure, then pageJob.js posts Job_returnToOutsourcer. That confirmation/setting gate is UI-only.

CRM2

No direct caller of Job_returnToOutsourcer was found. Do not infer that CRM2 exposes the CRM1 return-mode button.

Related endpoints