When to use this endpoint

Use Contract_new for CRM1 contract creation or when creating a contract inline from a job edit.

Use Contract_createData for CRM2’s mapped layout workflow, but account for its different metadata and expiry side effects.

Authentication and permissions

The request must establish an authenticated tenant context through signed API-key fields or a CRM session. The handler checks DBP but does not separately require a user ID.

No page or role-permission check is performed. created_by is taken from the authenticated session user.

Parameters

ParameterTypeRequiredDescription
nameStringYesTrimmed contract name. Blank and the false-like string "0" are rejected; maximum 64 characters. Names need not be unique.
notesStringNoTrimmed notes; defaults to blank. This route does not send mention notices.
expiryYYYY-MM-DD stringNoOptional expiry date. Blank stores null. The check verifies only shape, not calendar validity.
customJSON string or valueNoInitial custom values; defaults to an empty array. A string is JSON-decoded, then the value is JSON-encoded for storage. Invalid JSON therefore stores JSON null.
jobsJSON array stringNoJob IDs to move into this contract’s type-6 legacy link set. Defaults to []. Each value is integer-converted; IDs and duplicates are not validated.
addressStringNoInitial address; defaults to blank.
type_idInteger stringNoContract-type ID; defaults to 0 and is not validated.

Example request

$created = FM_api('Contract_new', [
	'name' => 'North Region Service Contract',
	'type_id' => '8',
	'notes' => 'Renewal review due in September.',
	'expiry' => '2027-09-30',
	'jobs' => json_encode([2039001, 2039002]),
]);

Example response

{
  "id": 720
}

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: name"}The trimmed name is empty or false-like.
{"error":"parameter too long: name. max length 64 characters"}The name exceeds 64 Unicode characters.
{"error":"invalid parameter: expiry"}A nonblank expiry does not match YYYY-MM-DD.
Server error/runtime type errorjobs is malformed JSON or decodes to a non-array; the handler passes it directly to array_map.

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

Behaviour and edge cases

  • The new row starts with meta.customersDirty=1. If jobs are supplied, a customer/asset rebuild runs immediately from direct jobs or, when none exist, the new legacy links.
  • Duplicate job IDs can create duplicate relationship rows. A positive nonexistent job ID can create an orphan link.
  • The route queues the type-104 worker that later fills date_completed when an expiry becomes due, but does not queue type-10/type-11 contract email notifications.

Side effects

  • Inserts the contract, optionally deletes each supplied job’s previous legacy contract link and inserts replacements, may rebuild customer/asset link rows, and writes a contract-created audit entry.
  • The row/link/cache/audit/cron operations are not wrapped in one transaction.

See it in Fieldmotion

CRM1

Use Create on the Contracts page, or choose add new from the Contract selector while editing a job. Filter Network requests for Contract_new.

CRM2

No direct production CRM2 call was found. CRM2’s configurable Contracts screens derive Contract_createData from their layout configuration.

Related endpoints