-
Notifications
You must be signed in to change notification settings - Fork 15
REST API Contracts
The complete usage guide for the Contracts module of the REST API β contracts, term tabs, suppliers and their contacts. Mirrors the interactive documentation at System β API β Documentation (with its live "Try it" tester).
Note
New to the API? The basics table on REST API: Tickets covers base URL, authentication, the response envelope, error codes, rate limits and PATCH semantics β identical across all modules.
What's distinctive about Contracts:
| β³ Renewal filters built in |
expiring_within_days, notice_within_days and expired are the module's own dashboard/Watchtower SQL shapes exposed as parameters β renewal reports are one call. |
| π’ Contract numbers can't collide via the API | The UI has no uniqueness check on contract_number; the API refuses duplicates with a 409 pointing at the existing contract. |
| π Suppliers get their full record | The lite picker list stays at GET /suppliers (under reference.read); the full CRUD β registration/VAT, address, questionnaire dates, contacts β lives under the new suppliers permission. The API can also set supplies_assets (the flag the Assets module filters suppliers by), which the UI never writes. |
| π Documents are links, not uploads | The module stores external DMS URLs (dms_link, dpia_dms_link) β plain string fields, no file upload exists or is needed. |
| πͺ The RFP Builder is not exposed | It's internal-only by design (suppliers never log in) and stays UI-only. |
Register a supplier and its contract, with renewal tracking from day one:
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_β¦"
# 1. Supplier (flagged as an asset supplier so it appears in Assets pickers)
SUP=$(curl -s -X POST "$B/suppliers" -H "$K" -H "Content-Type: application/json" -d '{
"legal_name": "Acme Print Ltd", "trading_name": "Acme Print", "supplies_assets": true
}' | jq -r '.data.id')
# 2. Contract with value, end date and notice date
curl -s -X POST "$B/contracts" -H "$K" -H "Content-Type: application/json" -d "{
\"contract_number\": \"CN-2026-014\", \"title\": \"Managed print services\",
\"supplier_id\": $SUP,
\"contract_start\": \"2026-08-01\", \"contract_end\": \"2028-07-31\",
\"notice_period_days\": 90, \"notice_date\": \"2028-05-02\",
\"contract_value\": 24000, \"currency\": \"GBP\"
}"| Parameter | Description |
|---|---|
q |
Search contract number, title and supplier legal name |
supplier_id Β· contract_status_id Β· contract_owner_id Β· payment_schedule_id
|
Id filters |
is_active |
true / false
|
expiring_within_days |
β³ Active contracts whose contract_end falls within N days (Watchtower's 30/90-day windows as a parameter) |
notice_within_days |
π Active contracts whose notice_date falls within N days β the "act now or auto-renew" report |
expired |
true = contract_end already passed |
ends_before / ends_after
|
YYYY-MM-DD bounds |
sort |
contract_end (default), contract_start, created_at, title, contract_number, contract_value, id β prefix - for descending |
page / per_page
|
Pagination β default 1 / 25, max 100 |
The contract shape:
{ "id": 4, "contract_number": "CN-2026-014", "title": "Managed print services",
"description": null,
"supplier": { "id": 5, "name": "Acme Print" },
"owner": { "id": 1, "name": "Administrator" },
"status": { "id": 2, "name": "Active" },
"payment_schedule": { "id": 1, "name": "Annual" },
"dates": { "start": "2026-08-01", "end": "2028-07-31",
"notice_date": "2028-05-02", "notice_period_days": 90 },
"value": { "amount": 24000.0, "currency": "GBP" },
"cost_centre": null, "dms_link": null,
"governance": { "terms_status": null, "personal_data_transferred": false,
"dpia_required": false, "dpia_completed_date": null, "dpia_dms_link": null },
"is_active": true, "created_at": "2026-07-03T15:40:52Z" }contract_number + title required; everything else optional. Lookup ids validated (422 naming the field), dates YYYY-MM-DD, currency a 3-letter code (lower-case is normalised). Duplicate contract_number β 409 with the existing contract's id β a deliberate API-only safeguard. Returns 201.
Everything creatable is patchable; null clears; renaming to a contract_number in use β 409. Set is_active: false to retire a contract without deleting it β usually the right move.
Warning
Permanent. The contract and its term-tab contents are removed; tasks, calendar events and RFPs that referenced it are unlinked (kept, not deleted). Prefer is_active: false for retirement.
Term tabs (Termination, Liability, β¦) are configured in Contracts β Settings; each contract stores its own content per tab.
Every active tab with this contract's content (null where nothing recorded).
{ "terms": [ { "term_tab_id": 1, "content": "Termination requires 90 days written notice." } ] }Per-tab upsert, exactly like the UI β only the tabs you send are touched. Returns the full term set.
The full record β registration/VAT numbers, address, questionnaire dates, type/status, supplies_assets, contract + contact counts, and the contact list inline.
Only legal_name is required. All identity/address/questionnaire fields accepted, plus supplies_assets β set it true for hardware vendors so they appear in the Assets module's supplier pickers (the UI can't set this flag; it's normally only flipped by the asset-import migration).
Deletes the supplier; its contracts, contacts and assets keep their rows but are unlinked (supplier set to none) β the same behaviour as the UI.
| Endpoint | Permission | Notes |
|---|---|---|
π’ GET /suppliers/{id}/contacts
|
π supplier_contacts.read |
The supplier's people |
π΅ POST /suppliers/{id}/contacts
|
π supplier_contacts.create |
first_name + surname required; email/mobile/job title/dial numbers optional |
π PATCH /suppliers/{id}/contacts/{contact_id}
|
π supplier_contacts.update |
Send only what changes |
π΄ DELETE /suppliers/{id}/contacts/{contact_id}
|
π supplier_contacts.delete |
Removes the contact |
Under the shared π reference.read permission (all populated via Contracts β Settings β empty on a fresh install):
| Endpoint | Returns |
|---|---|
π’ GET /contract-statuses
|
Contract statuses |
π’ GET /payment-schedules
|
Payment schedules |
π’ GET /supplier-types Β· GET /supplier-statuses
|
Supplier lookups |
π’ GET /contract-term-tabs
|
The configured term tabs |
π’ GET /suppliers
|
The lite supplier picker list (id, name, supplies_assets) |
A read-only key (contracts: read) feeds a monthly procurement report:
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_β¦"
# Contracts needing a renewal decision in the next 90 days, soonest first
curl -s -H "$K" "$B/contracts?expiring_within_days=90&sort=contract_end&per_page=100" \
| jq -r '.data[] | [.contract_number, .dates.end, (.supplier.name // "-"),
((.value.amount // 0) | tostring) + " " + (.value.currency // ""), .title] | @tsv'
# The urgent list: notice deadlines in the next 30 days (miss these and it auto-renews)
curl -s -H "$K" "$B/contracts?notice_within_days=30&sort=contract_end" \
| jq -r '.data[] | "β οΈ \(.dates.notice_date) \(.contract_number) \(.title)"'And the ERP direction β syncing supplier master data in:
SUP=$(curl -s -H "$K" "$B/suppliers?" ) # lite list via GET /suppliers (reference.read)
curl -s -X PATCH "$B/suppliers/5" -H "$K" -H "Content-Type: application/json" \
-d '{"vat_number": "GB123456789", "supplier_status_id": 2}'Under the hood: REST API β How It Works Β· Other modules: Tickets Β· Assets Β· Problems Β· Changes Β· Knowledge Β· Tasks Β· CMDB Β· Keys & permissions: System β API (System module) Β· Module docs: Contracts.
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)