patchContractEvent

patchContractEvent

Overview

Updates fields on an existing contract event without needing to delete and recreate it. This method requires the ContractEvents:Update permission to be associated with your role.

It performs the same function as editing an event on the Contracts → Events screen — the same row locking, audit trail, and downstream effects (keeping the contract's own details in sync, rebuilding allocation history) apply as when the edit is made on screen.

Permissions

The permission for this api is stored in [gb_api_permissions]permission as 'ContractEvents:Update'.

Only roles with a stored link to this permission in [gb_role_api_permissions] can run this api. By default, only the super role is granted this permission.

HTTP Method

Use the HTTP Method 'PATCH' for consuming this web service.

URL Examples

https://api.demo.catch-e.com/fm/contract/events/{contract_event_id} https://api.{environment}.catch-e.com/fm/contract/events/{contract_event_id} https://api.test.catch-e.com/fm/contract/events/{contract_event_id} 

Input Fields (Header)

Key

Format

Notes

Mandatory

Delegated-Locking-Session-Id

string

(Optional) Session id of a delegated lock already held on this contract event. If omitted, the API locks the event directly for the duration of the request.

No

Audit-User-Id

string

(Optional) User id to record against the audit trail for this change, instead of the authenticated user.

No

Time-Zone

string

Time zone used to interpret and format date/time values in the request and response.

No

Path Parameters

Key

Format

Notes

Mandatory

contract_event_id

integer

Identifies the contract event to update. Any contract_event_id sent in the request body is ignored — the event is always the one identified in the URL.

Yes

Input Fields (JSON)

Send only the fields you want to change. Any field left out of the request is left untouched.

{ "event_date": "2026-09-30", "due_date": "2026-09-30", "description": "Updated description", "contract_event_description_id": 100010, "event_value": "Updated value", "contract_event_value_id": 100015, "event_amount": 1234.56, "record_id": 100017, "table_name": "fm_client_cost_centres", "contract_event_action_id": 100001, "completed_flag": "no", "user_id": 11244 } 

(Illustrative values only — not real data.)

Field

Type

Notes

event_date, due_date

string (date, YYYY-MM-DD)

A zero date (0000-00-00) clears the date. An explicit empty string ("") is rejected — see Error Response Details.

description

string

Free text. Ignored if contract_event_description_id is also supplied in the same request — see "Linked value and description records" below.

contract_event_description_id

integer

Must belong to the event's own posting class. When supplied, its linked text is written to description, taking precedence over any description also sent in the same request.

event_value

string

Free text. Only used as sent for events not associated with a Cost Centre, Division or Driver record — see "Linked value and description records" below.

contract_event_value_id

integer

Must belong to the event's own posting class. When supplied, its linked text is written to event_value, taking precedence over any event_value also sent in the same request — except for Cost Centre, Division and Driver events, where event_value is always derived from record_id instead (see below).

event_amount

number

decimal(10,2), zero or greater. Commas in the input (e.g. "12,345.67") are accepted and stripped before validation. Values from 99999999 up are rejected — see Error Response Details.

record_id, table_name

integer, string

Cost Centre, Division and Driver events only — drives the linked record lookup. Must reference a record belonging to the contract's own client. For Driver events, a record belonging to another client that shares the contract client's client group is also accepted.

contract_event_action_id

integer

Must exist as a valid contract event action.

completed_flag

string

yes or no. Not re-defaulted on edit.

user_id

string

(Optional) The user this event is assigned to. Omitted, empty, or null leaves the current assignment unchanged. Must identify an existing user account. See "User assignment" below for what's required to change it.

The following fields cannot be changed via this endpoint: attachment_id (attachments are managed through the separate attach/detach endpoints), message_type (create-only), status_flag (use the delete endpoint to remove an event), and last_edit (always server-set from the audit user and current time).

contract_id and posting_class_id are immutable. They don't need to be sent, but if sent, the value must match the event's stored value or the request is rejected (see Error Response Details).

Linked value and description records

Two pairs of fields work the same way:

  • Send event_value on its own to set free text directly. Send contract_event_value_id to have the API derive event_value from that record instead — the derived text overrides any event_value in the same request. (Exception: for Cost Centre, Division and Driver events, event_value always comes from record_id, regardless of contract_event_value_id.)

  • Send description on its own to set free text directly. Send contract_event_description_id to have the API derive description from that record instead — the derived text overrides any description in the same request.

Cost Centre, Division and Driver events

For these three event types, record_id (together with table_name) identifies the linked Cost Centre, Division or Driver record, and the API always derives event_value from it — any event_value sent for these events is ignored.

The linked record must belong to the contract's own client. For Driver events only, a record belonging to a different client is also accepted if that client shares the contract client's client group; Cost Centre and Division records must belong to the contract's own client specifically. A record_id that doesn't exist, isn't active, or belongs to a client outside this scope is rejected — see Error Response Details.

User assignment

user_id identifies who the event is assigned to (this is separate from the audit trail — see the Audit-User-Id header above, which records who made the change, not who the event is assigned to).

  • Omitted, empty, or null leaves the current assignment unchanged.

  • Sending the event's own current assignment is always accepted and writes nothing, regardless of whether that account would otherwise qualify below — existence is still enforced.

  • A changed value must identify an existing user account. If it doesn't, the request is rejected with 422 user_id.noRecordFound.

  • A changed value must also be an account the Contracts → Events screen's own user picker would offer — that is, all of the following must be true: the account's access type is not external or web-services, its login is not the literal admin account, its status is not deleted or suspended, and if the account holds the super role, the caller making the request must also hold the super role. If any of these fail, the request is rejected with 422 user_id.invalidInput and the whole request is rolled back — no other fields in the same call are written either.

  • The audit author recorded against the change is unaffected by user_id — it's still the acting user (or the Audit-User-Id header value, if supplied).

Effect on the contract

If the event you're editing is the contract's most recent active event of certain types (Registration Number, Cost Centre, Division, Driver, or Location), the API recomputes that contract's corresponding field and updates it to match, rebuilds the contract's Cost Centre / Division / Driver allocation history, and syncs the change to Salesforce where Salesforce Apex sync is enabled for the tenant. Editing an older event of the same type does not change the contract.

Response Details

Success

200 - OK

{ "_links": { "self": { "href": "https://api.catch-e.loc/fm/contract/events/117157" } }, "_embedded": { "contract_event_id": 117157, "contract_id": 100237, "posting_class_id": 4, "event_date": "2026-09-30", "due_date": "2026-09-30", "description": "Updated description", "event_value": "Updated value", "event_amount": 1234.56, "record_id": 100017, "table_name": "fm_client_cost_centres", "contract_event_action_id": 100001, "completed_flag": "no", "user_id": 11244, "status_flag": "active" } } 

Error Response Details

Validation Mesage

Comments

404 - Not Found

"Invalid contract event id" — the contract_event_id in the URL doesn't exist.

422 - Unprocessable Entity

"This contract event has already been deleted."

422 - Unprocessable Entity

contract_id or posting_class_id was sent and differs from the event's stored value — both fields are immutable.

422 - Unprocessable Entity

The linked Cost Centre / Division / Driver record given in record_id doesn't exist or isn't active (e.g. "Cost Centre not recognised!" for a Cost Centre record).

422 - Unprocessable Entity

The linked Cost Centre / Division / Driver record given in record_id doesn't belong to the contract's client (or, for a Driver record, to a client sharing the contract client's client group).

422 - Unprocessable Entity

contract_event_value_id or contract_event_description_id doesn't belong to the event's posting class ("not associated with the posting class"), or doesn't exist.

422 - Unprocessable Entity

contract_event_action_id doesn't exist as a valid contract event action.

422 - Unprocessable Entity

completed_flag is something other than yes or no.

422 - Unprocessable Entity

event_amount is negative, non-numeric, or 99999999 or greater.

422 - Unprocessable Entity

event_date or due_date was sent as an explicit empty string.

422 - Unprocessable Entity

user_id doesn't identify an existing user account (user_id.noRecordFound).

422 - Unprocessable Entity

user_id names an account this event can't be assigned to — external/web-services access, the admin login, a deleted/suspended account, or a super-role account assigned by a non-super caller (user_id.invalidInput). The whole request is rolled back.

422 - Unprocessable Entity

The posting class recorded against this event no longer exists ("The posting class for this contract event no longer exists").

423 - Locked

The contract event is already locked by another session.

424 - Failed Dependency

A Delegated-Locking-Session-Id was supplied but no matching lock is held for this event.

403 - Forbidden

A Delegated-Locking-Session-Id was supplied but the held lock belongs to a different session or user (in addition to the standard permission-based 403 below).

{ "validation_messages": { "contract_event_action_id": { "noRecordFound": "A textual description of the validation exception" } }, "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Unprocessable Entity", "status": 422, "detail": "Failed Validation" } 
{ "validation_messages": { "posting_class_id": { "invalidRecord": "The posting class for this contract event no longer exists" } }, "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Unprocessable Entity", "status": 422, "detail": "Failed Validation" } 

401 Unauthorized

Validation Message Comments

401 Unauthorized

1. You have not authenticated before running this API or 2. The token_timeout of the current session has passed. You need to authenticate again.

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Unauthorized", "status": 401, "detail": "Unauthorized" } 

403 Forbidden

Validation Message Comments

403 Forbidden

- You do not have permissions for this request. - Go to System Roles and enter 'web_services' - Navigate to the Roles / APIs tab to make sure the permission you need to run this API is checked.

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Forbidden", "status": 403, "detail": "Forbidden" } 

406 Not Acceptable

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Not Acceptable", "status": 406, "detail": "Not Acceptable" } 

415 Unsupported Media Type

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Unsupported Media Type", "status": 415, "detail": "Not Acceptable" } 

500 Internal Error

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "string", "status": 599, "detail": "string" } 

default Unexpected Error

{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "string", "status": 0, "detail": "string" }