When to use this endpoint

Use the copy dialog workflow to duplicate an existing active job. This is a creation operation, not an in-place edit or an idempotent template lookup.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. Legacy edit-restriction bit 128 is enforced; client administrators retain the existing admin exception.

The primary job selection is tenant-scoped. There is no automatic schedule-conflict or assignee-ownership check. Cross-tenant follow-ups use persisted outsourcing context.

Parameters

ParameterTypeRequiredDescription
idInteger stringYesActive source job ID.
form_idsArray or JSON arrayYesNonempty target job-form IDs; each must exist, have type=0 and not be archived. One new job is attempted per user/form pair. Values are integer-coerced.
user_idsArray or JSON arrayNoDefaults to []. Empty means the source user ID; -1 also means source user; 0 unassigned. Positive IDs must be active tenant users. No list deduplication; copies use user_type=0.
do_not_copy_form_valuesInteger flagNoNonzero clears main-form answers; default 0 retains them. Changing form does not map answers into the new structure.
do_not_copy_subform_valuesInteger flagNoNonzero clears table answers; default 0 retains them. Stock is a separate flag.
do_not_copy_job_refInteger flagNoNonzero requests the configured next reference; default 0 retains the source reference. job-ref-method and job-ref-only-numeric still apply through creation.
do_not_copy_complete_statusInteger flagNoNonzero creates Incomplete; default 0 carries is_complete. It does not run completion actions merely because the copied status is Complete.
do_not_copy_stock_usedInteger flagNoExactly 1 clears stock; otherwise retains selected stock fields and resets every source to -1_0 (no source). Omission now follows the same no-source default.
do_not_copy_recurrence_dataPresence flagNoAny supplied value removes recurrence_triggered, recurrence_no and recurrence_previous_id before creation. It does NOT suppress copying recurrence_id or the recurrence itself.
ret_meeting_timeInteger flagNoNonzero adds the source meeting_time and meeting_time_e to the response.
accommodationJSON object, object or nullNoOverrides the source accommodation; omission carries it. Uses the existing accommodation normalizer, not an arbitrary metadata field. Normalized keys include name/address/phone/room_number/booking_reference, paired latitude/longitude, check_in/check_out and notes. Dates use YYYY-MM-DD HH:mm:ss; check_out must not precede check_in; coordinates must be paired and in range. Unknown keys are dropped; blank details normalize to null.

Example request

$result = FM_api('Job_copy', [
	'id' => '1042',
	'form_ids' => json_encode(['81']),
	'user_ids' => json_encode(['0']),
	'do_not_copy_complete_status' => '1',
	'do_not_copy_stock_used' => '1',
]);

Example response

{"ok":1,"job_ids":1088,"created_ids":[1087,1088],"rid":null}

job_ids remains the last scalar ID for existing callers. created_ids lists EVERY saved copy in creation order; rid remains only the last copied recurrence ID or null. A nested saved warning is retained with saved=1/warning/warnings.

A later creation failure returns error plus the saved created_ids prefix and saved=1 when nonempty. It does not undo earlier copies; reconcile that prefix before retrying.

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":"missing or invalid parameter: id"}Missing/nonpositive source ID.
{"error":"missing or invalid parameter: form_ids"}Missing/undecodable target list.
{"error":"missing or invalid parameter: user_ids"}Undecodable user list.
{"error":"job does not exist"}Missing/deleted source.
{"error":"error when copying job. please copy this and send it to FieldMotion to be looked into: …"}Job_new failed; the message embeds its response. Earlier copies or copied recurrence rows can already exist.
{"error":"Invalid target job form"}A target ID is missing, archived or not a job form; no copies are created.
{"error":"Invalid job assignee"}A selected source/target user does not resolve to an active tenant user.

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

Behaviour and edge cases

  • Prevalidates a nonempty target-form list and all tenant-user IDs before creation. Target forms must be active job forms; user 0 is unassigned and -1 resolves the source user's numeric ID. Outsource assignments are not preserved as outsource type by copying.
  • Creates every user/form pair without deduplicating either input list. Changing form does not map source answers into the new question structure.
  • Copies the source schedule, customer/asset, contract, notes, attendees, priority, Job Type, department and selected answer/cost inputs. Job_new assigns a fresh creator/time and work-calendar completion estimate; this is not a historical clone.
  • Resets subStatus to 0, removes viewing/on-route/in-progress metadata and strips source outsourcing relationships, so editing a copy cannot update the source job's remote counterpart. Accommodation is retained unless overridden; note entries use content, optional id/createdby and noteTime/editedTime in YYYY-MM-DD HH:mm:ss.
  • Each pair can get its own recurrence copy. do_not_copy_recurrence_data removes selected trigger metadata, NOT recurrence_id; the recurrence-days setting supplies lead time. No batch size cap or idempotency key.
  • Retained stock rows always start with source=-1_0 (no source), including when the stock flag is omitted. This avoids consuming the source job's inventory allocation again.
  • Job_new is invoked through the merging PHP request helper. Accepted outer creation controls can also affect it; avoid unrelated editor fields.

Side effects

  • Runs Job_new per pair: job/contract links, history, customer counts, answer/table saves, optional stock handling, asset tracking, configured events and notification scheduling. Existing copied stock allocations are not replayed.
  • Copies recurrence rows and rewrites their job-ID caches. Does not clone source quote/invoice relation rows.

See it in Fieldmotion

CRM1

Open Jobs, choose Copy, select users/forms and the reference/answer checkboxes; filter Job_copy. jobCopy.js JSON-encodes both lists and warns that a recurrence is also copied.

CRM2

Choose Copy in the Jobs module. moduleJobs.js sends user_ids/form_ids and separate completion/reference/answer flags; its table-and-stock switch sends both subform and stock flags. Recurring-job copying can then issue Job_setMeetingTime.

Related endpoints