When to use this endpoint

Use when a job or asset-maintenance workflow needs a new recurring sequence. Normal job creation/save establishes the example job afterward; this standalone endpoint creates configuration only.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. All records resolve in the authenticated tenant. This handler has no additional Job edit-bit, department-visibility or owner check.

Parameters

ParameterTypeRequiredDescription
nameStringNoDefaults to "no name". At most 255 characters by Core_maxLengthError; blank is allowed.
activeInteger-like scalarNointval; default 0. This create path does not restrict it to 0/1.
scheduleJSON stringNoDefault {}. Decoded with associative arrays and re-encoded with JSON_FORCE_OBJECT, including nested arrays. Falsy decoded input becomes an empty object. No focused-setter schedule validation.
copy_user, copy_cust_ref, copy_job_refInteger stringsNoOmitted/blank values use database defaults (normally null). Loose integer validation; no boolean range check and no -1-to-null translation.
every, customer_id, customer_type, skip_weekendsInteger stringsNoLoose integer validation without range or referenced-record validation. Omitted values use schema defaults; every normally null, others 0. Customer type 0 is customer, 1 is asset in consumers.
on_arrStringNoStored verbatim; not validated against every. Use the frequency formats documented by JobRecurrence_set.
customJSON textNoTrimmed and stored only if longer than two bytes. Invalid JSON can fail database persistence.
copy_job_valueScalarNoMetadata value, default integer 1. Supplied value is retained, not normalized to boolean.
due_date_offsetInteger-like scalarNoMetadata offset, intval; default 0, negative values are not rejected here.
loop_recurrence, copy_form_valuesInteger-like scalarsNoDefault 0; copied into metadata only when isCRM2 is supplied and loosely true.
isCRM2Scalar flagNoTruthy value enables the newer metadata flags. Presence alone, even a false value, changes the expiry-notification branch.
expiry_dateDate stringNoStored as edate when truthy and not exactly 0000-00-00; otherwise null. This path does not validate calendar dates.
notesStringNoPassed to the checked notes setter after insertion; plain text becomes a content entry, JSON arrays are retained.

Example request

$result = FM_api('JobRecurrence_create', ['name'=>'Monthly checks', 'active'=>'0', 'schedule'=>'{}']);

Example response

{
  "id": "1042",
  "name": "Monthly checks",
  "ids": "",
  "cdate": "2026-10-15",
  "edate": null,
  "active": "0",
  "every": null,
  "on_arr": null,
  "customer_id": "0",
  "customer_type": "0",
  "next_date": null,
  "user_id": "0",
  "notes": null,
  "files": null,
  "edited_uuid": "JobRecurrence_create",
  "last_edited": "2026-10-15 10:00:00",
  "days_in_advance": "30",
  "copy_user": null,
  "copy_cust_ref": null,
  "department_id": "0",
  "form_id": "0",
  "schedule": "{}",
  "meta": "{\"copy_job_value\":1,\"due_date_offset\":0}",
  "custom": null,
  "copy_job_ref": null,
  "created_by": "92442",
  "skip_weekends": "0"
}

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":"parameter too long: name. max length 255 characters"}Name exceeds the character limit.
{"error":"Job Recurrence field \"every\" should be an integer","errors":[{"msg":"Job Recurrence field \"every\" should be an integer","val":"x"}]}A validated integer field fails the legacy integer check; field/value vary.
{"error":"could not create job recurrence"}Insert does not return a positive ID. Later follow-up failures need not become this error.

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

Behaviour and edge cases

  • Creating configuration alone does not create or attach an example job. Normal job creation/save and asset-maintenance creation call this internally, then establish job linkage.
  • The complete stored row is returned, not just its ID. Database numeric fields are normally strings; notes, schedule, meta and custom remain JSON-encoded strings. The example uses a 30-day tenant generation horizon; the actual value comes from recurrence-days.
  • created_by is the session parent account ID rather than necessarily the acting sub-user. cdate is a date column, so its inserted datetime loses the time.
  • This is not the strict configuration setter: integer ranges, target existence, frequency and schedule consistency are not checked. User/form/department/ids/next_date supplied directly are not creation inputs.
  • Mobile clients were checked separately: recurrence notes/files are synchronized through m/www syncDownloads/syncDownloadOne and notes uploads, not direct calls to this endpoint. Those intermediary contracts are not expanded by this API route.

Side effects

  • Inserts a tenant recurrence and a global worker registration with last-job ID 0, current last-job date and recurrence-days; registration is attempted even for inactive configurations. It does not run generation synchronously.
  • Optional notes invoke the checked notes setter and history. Its result is ignored by create; the returned row is read afterward. The tenant insert is checked, but notes, registration and notification steps are not one distributed transaction.
  • With expiry and no isCRM2 parameter, creates a type-7 reminder using strtotime(expiry_date) minus the notification_types.job_recurrence_expires_soon.num lead days. With isCRM2 present, calls the mapped create notification instead.
  • For crmVersion=2, sends mention notices using mapped request values; the newly inserted ID is not injected into that request, so the notice link can contain 0.

See it in Fieldmotion

CRM1

Create or edit a job and configure recurrence, or create asset maintenance. Inspect Job_new / Job_save / AssetMaintenance_create: the recurrence create call is internal, not necessarily a separate Network request.

CRM2

Configure recurrence in the job editor and inspect Job_save, which calls this internally. Newer flags depend on isCRM2 carried into the recurrence payload.

Related endpoints