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

ParameterTypeRequiredDescription
idInteger stringYesPositive contract ID. The route does not perform an existence lookup before updating and scheduling.
valStringYesYYYY-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

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"}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.num tenant 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_date when due but does not change active.

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