Contracts
Set contract expiry date
/a/Contract_setExpiryDate
Set or clear a contract expiry and replace its email-notification and completion-date schedules.
When to use this endpoint
Use Contract_setExpiryDate whenever an expiry change must synchronize every current expiry side effect.
It is the safest expiry path for CRM1 and integrations; the legacy full edit and both create routes do not schedule the same work.
Authentication and permissions
The request must authenticate with signed API-key fields or a logged-in CRM session. The handler performs no additional page or role-permission check.
The lookup and any write use the authenticated tenant; an ID from another tenant cannot be addressed through this call.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer string | Yes | Positive contract ID. The route does not perform an existence lookup before updating and scheduling. |
val | String | Yes | YYYY-MM-DD, blank to clear, or legacy 0000-00-00 which is normalized to blank/null. The regex checks shape rather than calendar validity. |
Example request
$result = FM_api('Contract_setExpiryDate', [
'id' => '720',
'val' => '2027-09-30',
]);
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"} | The ID is absent or nonpositive. |
{"error":"missing or invalid parameter: val"} | The val key is omitted. |
{"error":"invalid parameter: expiry"} | The value is not a string, or a nonblank value does not match YYYY-MM-DD. |
{"error":"could not update contract expiry"} | The database update reports failure. A zero-row match may not be reported as failure by the database helper. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Clearing expiry stores SQL null and cancels pending contract email/status schedule rows. It does not clear an existing
date_completed. - The
notification_types.contract_expires_soon.numtenant setting supplies the nonnegative days-before offset for the type-10 email row; missing/invalid values become zero. - A valid expiry creates a type-10 “expires soon” row, a type-11 “expiry” row, and a type-104 worker row. The email worker later decides whether configured notifications are enabled.
- The type-104 worker fills
date_completed=expiry_datewhen due but does not changeactive.
Side effects
- Updates
expiry_date/last_edited, replaces three groups of global cron work, and writes a contract audit entry. These operations are not transactional.
See it in Fieldmotion
CRM1
Click the Expires date on the Contracts page and choose or clear a date. Filter Network requests for Contract_setExpiryDate.
CRM2
CRM2 writes expiryDate through Contract_updateData, which calls the same schedule helpers after a successful mapped update.
Related endpoints
Contract_setActivecontrols active/completed status separately.Contract_updateFieldcan apply the same expiry side effects to multiple IDs.Contract_newqueues only the completion-date worker at creation.