Jobs: recurrence settings
Set or clear recurrence expiry
/a/JobRecurrence_setEDate
Change the sequence end date, refresh its scheduler expiry and replace the expiry reminder.
When to use this endpoint
Use for the recurring-jobs expiry cell. A selected expiry preserves jobs through that local day; clearing it removes the limit without deleting children.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Tenant context is required. The Job edit-restriction bit 128 applies, with the existing client-administrator exception.
IDs resolve inside the authenticated tenant. There is no additional department-visibility or recurrence-ownership filter.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer string | Yes | Positive recurrence ID in canonical integer form; not a job ID. The record must exist. |
val | String | No | YYYY-MM-DD or blank to clear. Omitted/blank and exact zero-date sentinels normalize to null; invalid calendar dates or timestamp strings are rejected. |
skip-run | Legacy truthy flag | No | Default false. A truthy value suppresses only the scheduler-priority bump. It does not suppress the settings save, explicit cleanup, expiry registration updates or reminder reconciliation. |
Example request
$result = FM_api('JobRecurrence_setEDate', ['id'=>'1042', 'val'=>'2027-12-31']);
Example response
{"ok":1,"rec_update":{"ok":1}}
A post-save follow-up failure adds saved=1 and warning/warnings without undoing the settings. Read the warning and reload affected objects rather than blindly replaying the operation.
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"} | ID missing, invalid or not positive. |
{"error":"job recurrence 1042 does not exist"} | No matching recurrence; numeric ID varies. |
{"error":"No permission to edit"} | The Job edit restriction applies and the caller is not a client administrator. |
{"error":"Unable to save job delivery changes"} | The checked local transaction failed; settings/history are rolled back. |
{"error":"Invalid saved recurrence metadata"} | The saved metadata cannot be decoded as an array/object; it is not silently erased. |
{"error":"missing or invalid parameter: val"} | The value is missing when required, has an unsupported type, or fails the operation-specific range/shape/date rules. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Saves the validated expiry first. A nonblank expiry then removes only active incomplete cached children beyond that account-local end day, never the first valid anchor or completed/deleted jobs.
- The cutoff is the next local midnight, not a fixed 86400-second addition across DST. Past work is never removed by expiry cleanup.
- Clearing expiry performs no child cleanup. Explicit user/form reset and pause remain separate reset-from-now workflows.
- If generation is currently marked building, cleanup returns a busy error rather than forcing a stop; the setter exposes it as saved warning with cleanup details.
- Global expiry/registration and type-7 reminders are reconciled after the local save. Reminders are created only for active sequences with an expiry, using notification_types.job_recurrence_expires_soon.num.
- rec_update reports the priority reconciliation result when enabled, or null with skip-run. Top-level saved warnings flag follow-up failures.
- A priority bump does not synchronously generate jobs: it backdates global last_run by seven days. Missing active registration is created using recurrence-days. Inactive sequences have their registration removed without being regenerated; an active sequence with blank on_arr yields a saved warning instead of a misleading rolled-back error.
- The surrounding Job_save recurrence editor invokes this setter internally. Its wider generation-setting save separately requests reset-from-now and now propagates failures/saved warnings. Direct endpoint effects above do not describe the whole editor save.
Side effects
- The existing recurrence is locked and changed settings, edit timestamp/operation marker and history are committed together in a checked local transaction. Failed local persistence rolls back; an unchanged value normally returns ok without a new local write.
- Cleanup, child-target changes and global scheduler/reminder reconciliation run after the local save. A failed follow-up preserves committed settings and returns ok=1, saved=1, warning/warnings. Inspect current state and any partial progress before retrying; tenant and global effects are not distributed-atomic.
See it in Fieldmotion
CRM1
Open Jobs → Recurring Jobs and edit End/Expiry Date; watch JobRecurrence_setEDate. The asset maintenance and customer recurrence screens also use it.
CRM2
Edit recurrence expiry in the recurring-jobs module; its dialogs send the new date to JobRecurrence_setEDate. The shared job recurrence editor also reaches this setter indirectly through Job_save; observe Job_save in the Network panel rather than expecting a separate request to this focused route.
Related endpoints
JobRecurrence_setActivecontrols whether the sequence is enabled.JobRecurrence_getreloads the saved expiry.