Repository navigation
REST API Ticket Related Developer Guide
How GET /tickets/{id} came to say what is on a ticket and what it is linked to, and how GET /tickets/{id}/attachments lists its files. Built for #328 (5.2.0), asked for by pappas81. User docs: REST API - Tickets (the related block under GET /tickets/{id}, and GET /tickets/{id}/attachments).
The one-line version: one new file, api/v1/resources/ticket_related.php, with one function - apiTicketRelated($conn, $ticketId, $apiKey) - that three places call: the single GET, the list (only with ?include=related), and the webhook engine's Full record loader for tickets. Passing the API key makes it leave out what the key could not read itself; passing null (a webhook) gives everything.
Before 5.2.0, GET /tickets/{id} - and the ticket's Full record webhook, which is the same serialiser - said nothing about what hung off the ticket. An integration that wanted the whole picture called /notes, /thread, /forms, /checklists, /watchers... in turn, most of them returning []. And there was no way at all to learn what the ticket was linked to (tasks have a ticket_id; tickets had nothing pointing the other way), or what files were attached.
before after
GET /tickets/42 GET /tickets/42
GET /tickets/42/notes -> [] related.counts -> { notes: 0, messages: 2, attachments: 1, forms: 0, ... }
GET /tickets/42/thread -> [2] related.links -> [ {type: task, id: 41}, {type: ticket, relation: duplicate_of} ]
GET /tickets/42/forms -> [] GET /tickets/42/thread (worth calling)
GET /tickets/42/checklists -> [] GET /tickets/42/attachments (worth calling)
...
| File | π¨ | What changed |
|---|---|---|
api/v1/resources/ticket_related.php |
π |
new: apiTicketRelated(), apiTicketAttachments(), the handler apiTicketAttachmentsList()
|
api/v1/resources/tickets.php |
π | requires it; apiTicketsGet() adds related; apiTicketsList() adds it with ?include=related
|
api/v1/lib/routes.php |
π | GET /tickets/{id}/attachments |
api/v1/lib/permissions.php |
π | permission resource ticket_attachments (read) |
api/v1/lib/modules.php |
π |
ticket_attachments belongs to Tickets (always on) |
api/v1/index.php |
π | the route in the root endpoint list |
workflow/includes/engine.php |
βοΈ | the ticket Full record loader appends related (with $apiKey = null) |
api/workflow/webhook_test.php |
βοΈ | the editor's Send test sample does the same, so the preview matches a real send |
api/v1/spec.json |
π | the new route; include on GET /tickets; GET /tickets/{id} describes related
|
api/v1/lib/openapi_schemas.php |
π | typed TicketRelated and TicketAttachment; related on Ticket and TicketDetail
|
includes/feature_bingo/cards/system-integrations.php |
π― | system.api_ticket_related |
tests/api-ticket-related.php |
π§ͺ | new: 16 checks over real HTTP |
No schema change - every table it reads already existed.
"related": {
"counts": { "notes": 3, "messages": 5, "attachments": 2, "forms": 1,
"checklists": 0, "watchers": 2, "time_entries": 0 },
"links": [
{ "type": "task", "id": 41, "name": "Order laptop" },
{ "type": "problem", "id": 7, "reference": "PRB-0007", "name": "VPN drops" },
{ "type": "ticket", "id": 990, "reference": "TKT-0990", "relation": "duplicate_of" },
{ "type": "external_issue", "provider": "jira", "reference": "OPS-12",
"url": "https://example.atlassian.net/browse/OPS-12", "status": "In Progress" }
]
}Counts, not booleans. The issue asked for notes_attached: true/false. A count answers the same question (> 0) and the next one too (is it worth paging?), for the same query.
One count per sub-endpoint, named for what the endpoint returns, so the mapping is obvious:
| count | endpoint | permission | how it is counted |
|---|---|---|---|
notes |
/notes |
ticket_notes |
COUNT(*) FROM ticket_notes |
messages |
/thread |
ticket_thread |
COUNT(*) FROM emails |
attachments |
/attachments |
ticket_attachments |
count(apiTicketAttachments()) - the list itself, so they can never disagree |
forms |
/forms |
ticket_forms |
count(TicketForms::forTicket()) - the endpoint's own call |
checklists |
/checklists |
ticket_checklists |
COUNT(*) FROM ticket_checklists |
watchers |
/watchers |
ticket_watchers |
count(TicketWatchers::list()) - it leaves out inactive analysts, so a COUNT would not match |
time_entries |
/time-entries |
ticket_time_entries |
COUNT(*) ... AND is_active = 1, the endpoint's filter |
TRAP: a count must match what its endpoint returns. Where the endpoint filters (watchers drop inactive analysts, forms come from the host logic), the count calls the same service rather than writing a second query that would drift.
related must never tell a key more than it could find out by calling the endpoints itself. So:
// api/v1/resources/ticket_related.php
$can = function (string $perm) use ($apiKey): bool {
if ($apiKey === null) return true; // a webhook - see below
return in_array('read', $apiKey['permissions'][$perm] ?? [], true);
};
...
if ($can('ticket_notes')) $counts['notes'] = $scalar("SELECT COUNT(*) FROM ticket_notes WHERE ticket_id = ?");-
A count appears only with
readon its endpoint's permission. A key withtickets.readalone gets"counts": {}. -
A link appears only with
readon that record's permission (tasks,problems,changes,projects,assets,cmdb_objects) and if the record is in one of the key's companies:
$inScope = function (string $table, int $id) use ($conn, $apiKey): bool {
return $apiKey === null || apiKeyCanAccessTenantRow($conn, $apiKey, $table, $id);
};-
A linked ticket goes through
apiKeyCanAccessTicket()- company and the key's analyst's departments, the same gate asGET /tickets/{id}. -
A linked ticket never carries its subject, only its number and the relation. The other ticket may be confidential, and on the webhook path nothing redacts a ticket that is not the one the event is about. (The ticket the event IS about is still handled by
ticketRedactForOutbound()- a confidential ticket gets no.fullat all.) -
A webhook passes
nulland gets everything: whoever set up the workflow chose to send the record, as with every other field of.full.
TRAP: empty counts must be {}, not []. PHP encodes an empty array as [], which the OpenAPI shape check (rightly) calls a wrongly-serialised object. The function returns $counts ?: new stdClass().
Six record kinds come from a table of [type, permission, table, SQL], each SQL giving id, reference and name:
$kinds = [
['task', 'tasks', 'tasks', "SELECT id, NULL AS reference, title AS name FROM tasks WHERE ticket_id = ? ORDER BY id"],
['problem', 'problems', 'problems', "SELECT p.id, p.problem_number AS reference, p.title AS name FROM problem_tickets pt JOIN problems p ON p.id = pt.problem_id WHERE pt.ticket_id = ? ORDER BY p.id"],
['change', 'changes', 'changes', "... FROM change_tickets ct JOIN changes c ..."],
['project', 'projects', 'projects', "... FROM project_tickets pt JOIN projects p ..."],
['asset', 'assets', 'assets', "... FROM ticket_assets ta JOIN assets a ..."],
['cmdb_object', 'cmdb_objects', 'cmdb_objects', "... FROM ticket_cmdb_objects tc JOIN cmdb_objects o ..."],
];Adding a kind is one row. Each query is in its own try, so a module whose tables Database Verify has not created yet simply links nothing.
Ticket to ticket reuses ticketLinksFor() from includes/ticket_links.php - the very grouping the ticket screen draws - and turns its groups into a relation from THIS ticket's side:
$g = ticketLinksFor($conn, $ticketId); // parent, children[], duplicate_of, duplicates[], related[]
if ($g['parent']) $links[] = $one($g['parent'], 'child_of');
foreach ($g['children'] as $t) $links[] = $one($t, 'parent_of');
if ($g['duplicate_of']) $links[] = $one($g['duplicate_of'], 'duplicate_of');
foreach ($g['duplicates'] as $t) $links[] = $one($t, 'duplicated_by');
foreach ($g['related'] as $t) $links[] = $one($t, 'related');Merges add merged_into_this from ticket_merges (the merged ticket is in the trash; GET /tickets/{id}?deleted=true still finds it). External tracker issues come from integration_links joined to integration_connections for the provider - key, address and status in the tracker - under tickets.read, since they are part of the ticket.
Attachments were the one thing with no endpoint at all, so a count alone would have been a dead end. apiTicketAttachments() reads two places:
| source | from | left out |
|---|---|---|
message |
email_attachments joined to the ticket's emails
|
is_inline = 1 - a signature's logo or a picture shown in the body is part of the message, and would bury the real files |
note |
document_links with parent_type = 'ticket_note' on the ticket's notes, joined to documents
|
deleted documents |
Tickets have no Documents panel - files on a ticket live on its notes - which is why a note document's source_id is the note.
A document of kind files (a link to a file in the Files module, #303) is listed without its name: in the app the name is shown only to someone who can open the file's folder, and the API does not check Files permissions. It says there is a file here, nothing about it.
It lists; it does not download. Downloading over the API would need its own design (streaming, storage drivers, Files permissions) and was not asked for.
// api/v1/resources/tickets.php - apiTicketsList()
if (in_array('related', array_map('trim', explode(',', (string)($_GET['include'] ?? ''))), true)) {
foreach ($tickets as &$tk) $tk['related'] = apiTicketRelated($conn, (int)$tk['id'], $apiKey);
unset($tk);
}related is about a dozen small queries per ticket. On one ticket that is nothing; on a page of 100 it is 1,200, for callers who mostly do not want it. include is a comma list so another opt-in can join it later.
The Full record loader for tickets appends it, exactly as the API does but with null:
// workflow/includes/engine.php - fullObjectLoaders()
'ticket' => $one('tickets.php', 'apiTicketSelect', ' WHERE t.id = ? LIMIT 1',
fn($c, $r) => apiSerializeTicket($r) + ['related' => apiTicketRelated($c, (int)$r['id'], null)]),So {{ticket.full.related.counts.attachments}} works in any action, and Send test in the editor (api/workflow/webhook_test.php) builds its sample the same way, so the preview is what a real send carries.
FREEITSM_TEST_DATABASE=<throwaway db> FREEITSM_TEST_URL=http://localhost/<that install> php tests/api-ticket-related.php
Two ZZ tickets (one the parent of the other, the child's subject containing SECRET), a note with a document, a message with a real attachment and an inline picture, a task. Two temporary keys over real HTTP:
-
the full key - counts are 1 note, every message, 2 attachments (the inline picture left out), and forms / checklists / watchers / time entries all present; links hold the task by id and name and the child as
parent_ofby number; nothing anywhere saysSECRET; from the child, the main ticket ischild_of. -
the narrow key (
tickets.readonly) -countsis{}; no task link; the ticket link stays. -
/attachmentslists the message file and the note document with names, types, sizes andsource_id; 403 withoutticket_attachments.read. -
GET /tickets?include=relatedadds it to every row; without it the list is unchanged. - the webhook path -
enrichWithFullObjects()givesticket.full.relatedwith all seven counts and both links.
The OpenAPI document generated with the new schemas passes openapi_check.php and validates against the OpenAPI 3.0 meta-schema; openapi_verify.php against a live install finds nothing wrong with related.
- A count must match its endpoint - call the endpoint's own service where it filters.
-
$counts ?: new stdClass()- an empty object, not[]. - Never a linked ticket's subject.
-
$reftakes no siblings in OpenAPI 3.0 - adescriptionbeside'$ref' => '#/components/schemas/TicketRelated'is ignored, and some validators reject it. The note went in a PHP comment. -
Adding a sub-endpoint to tickets? Add its count here too, under its own permission, or
relatedquietly stops being the whole picture.
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
-
Architecture
- β³ π§Ή Root folder tidy (URL routing)
- β³ π Database Integrity (FKs & constraints)
- β³ π οΈ Database Verification β Developer Guide
- β³ π§© Service Layer (UI + API share code)
- β³ πͺ€ Code traps (the TRAP: comments)
- β³ π Commenting for the Engineering wiki
- β³ π οΈ Engineering wiki scanner - Developer Guide
- β³ π Service-Layer progress
- π€ Contributing (read before a pull request)
- π§ͺ Developer tests
- π PDF exports moved to PDFKit (#254)
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- π Date & Time Formats
- π± Currencies
- π§ The sidebar (optional module rail)
- π§© Preference templates
- π Display order (modules, Watchtower cards) β Developer Guide
- Theming & Dark Mode
- ποΈ Recent β getting back to what you were doing
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
-
MobileβFriendly
- β³ π« Mobile: Tickets
- β³ π» Mobile: Assets
- β³ π Mobile: Calendar
- β³ π Mobile: Knowledge
- β³ π¦ Mobile: Service Status
- β³ πΌ Mobile: Watchtower
- β³ π§© Mobile: Problem Management
- β³ π Mobile: Change Management
- β³ πΏ Mobile: Software
- β³ β Mobile: Tasks
- β³ π Mobile: Forms
- β³ π Mobile: Contracts
- β³ π Mobile: Domains
- β³ π Mobile: People
- β³ π Mobile: Projects
- β³ ποΈ Mobile: Files
- β³ π Mobile: LMS
- β³ πΊοΈ Mobile: CMDB
- β³ πΊοΈ Mobile: Network Mapper
- β³ π§ Mobile: Process Mapper
- β³ βοΈ Mobile: Workflow
- β³ π₯οΈ Mobile: System
- β³ π Mobile: Reporting
- β³ π Mobile: System Wiki
- β³ π Mobile: Self-Service Portal
- β³ π§° Mobile: Techniques & Tricks
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- β³ π Switching modules off
- β³ π οΈ Module availability β Developer Guide
- β³ π Module availability β design (#217)
- 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
- β³ π‘οΈ CSRF protection (S4) β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
-
π¦ Microsoft Entra ID
- β³ π₯ Importing people and groups
- β³ π» Intune: assets to their primary user
- β³ π’ Organisation chart
- β³ π οΈ Entra directory sync β Developer Guide
- β³ π οΈ Entra import - review (#235)
- β³ π οΈ Entra follow-ups - review (#237-#240)
- β³ π οΈ Intune primary user - review (#236)
- β³ π οΈ Organisation chart - reviews (#242, #265)
- π CardDAV contact sync
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π Proposal: custom fields, inventory import and change evidence (#194)
- β³ π οΈ Custom fields, evidence + inventory - review (#195-#197)
- β³ π οΈ Long forms in a task's Work view - review (#198)
- β³ π οΈ Empty Procedures fold - review (#247)
- β³ π« 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: Domains
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ π·οΈ REST API: Cost centres
- β³ π REST API: Chart of accounts
- β³ π REST API: Projects
- β³ π‘οΈ API threat protection
- β³ π§βπΌ REST API: Analysts
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Reply subject and replying to one message
- β³ π Live updates
- β³ π οΈ Watching a ticket - Developer Guide (1 of 2)
- β³ βοΈ Ticket address suggestions - Developer Guide
- β³ π οΈ CSAT delay and reminder - Developer Guide
- β³ π οΈ Ticket checklist step types - Developer Guide (1 of 2)
- β³ π οΈ Right-click Attach checklist - Developer Guide
- β³ π οΈ Checklists in the REST API - Developer Guide
- β³ π A ticket's related block and attachments - Developer Guide
- β³ π οΈ Inbox.js map β Developer Guide
- β³ π οΈ Floating windows & the file viewer β Developer Guide
- β³ π οΈ Tickets settings β Developer Guide
- β³ π Simpler ticket and task forms - design (#218)
- β³ ποΈ The ticket workspace
- β³ π Forms on tickets
- β³ π The ticket table
- β³ π Rota copy and paste β Developer Deep Dive
- β³ β Checklists & SOPs
- β³ βοΈ Mandatory fields
- β³ π§Ύ Custom ticket fields
- β³ π·οΈ Ticket categories
- β³ π§Ύ A type for every new ticket
- β³ π₯ Assigning tickets to a team, and escalation
- β³ π’ One board across every company
- β³ π Ticket dashboard β Developer Guide
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ π Attachment size limits and large emails
-
β³ Basic IMAP mailboxes
- β³ π Basic IMAP without the PHP extension (#257)
- β³ π οΈ Basic IMAP client β Developer Guide
- β³ π§ͺ Basic IMAP client β Testing and verifying
- β³ π οΈ Basic IMAP - Sent copy - Developer Guide (#270)
- β³ π οΈ Verifying a mail folder β Developer Guide
- β³ π οΈ Mailbox providers β Developer Guide
- β³ π οΈ How Gmail mail collection works β Developer Guide
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
-
β³
βοΈ Telegram channel - β³ β CSAT company scope and filters β Developer Guide
- β³ π₯ Microsoft Teams channel
- β³ π¨οΈ Mattermost channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ β Record previews
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ π¨ Telling the analyst a ticket is theirs
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ π Confidential tickets
- β³ π₯ Portal managers
- β³ π Who has seen a ticket
- β³ π Reading long tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π½ Just my tickets, or no closed ones
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Case reports - a ticket and its work as one PDF
- β³ π Scheduled work in your own calendar
- Problem Management
-
Tasks
- β³ π οΈ Task board and subtasks β Developer Guide
- β³ π§βπ€βπ§ People on a task ("Involved")
- β³ π Repeating tasks
- β³ π’ Moving a task between companies
- π Projects
-
Assets
- β³ π’ Moving an asset between companies
- β³ π Shared asset locations
- β³ π§βπΌ Assigning assets to analysts
- β³ π Warranty and lease alerts
- β³ π Leases
- β³ π Saved table views
- β³ π¨οΈ Recording anything, and importing it
- β³ π§© Asset type layouts
- β³ π Inventory freshness
- β³ π Linked configuration item
- β³ π Connected assets
- β³ π Asset review
-
β³ π·οΈ QR asset labels
- β³ π οΈ QR asset labels β Developer Guide
- β³ π Asset label designer - design (#229)
- β³ π· Asset scanning β Developer Guide
- β³ π οΈ Asset tag numbering β Developer Guide
- β³ π οΈ Asset reconciliation β Developer Guide
- β³ π οΈ Reconciliation, tags + labels - review (#164)
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ πͺ Hyper-V and Failover Clusters
- β³ π Linking equipment to tickets
- β³ βοΈ Follow-up tasks on a ticket
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
-
Forms
- β³ π¨ The form designer β Developer Guide
- β³ π Layout & the grid β Developer Guide
- β³ ποΈ Collections β grouping submissions
- β³ π Submissions as PDFs
- β³ β‘ What happens next β a form's own actions
- β³ π οΈ Sections & conditional logic β Developer Guide
- β³ π οΈ Lookup fields β Developer Guide
- β³ π‘οΈ Catalogue request approvals
- People
- Starters & leavers
- Domains
- ποΈ Files
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
-
CMDB
- β³ π οΈ CMDB β Developer Guide
- β³ π οΈ Impact analysis β Developer Guide
- β³ π οΈ Data quality β Developer Guide
- β³ π Linked assets
- β³ π Linking an asset to its CI - design (#201)
- β³ π Discovery and redundancy-aware impact - design (#199)
- β³ π οΈ Relationship wording - review (#297)
- Network Mapper
-
Workflows
- β³ π οΈ Workflow engine β Developer Guide
- β³ π οΈ Workflows for tasks β Developer Guide
- β³ π οΈ Workflow notes on a ticket β Developer Guide
- β³ π οΈ Workflow category routing β Developer Guide
- β³ β° Time-Based Triggers
- β³ πͺ Webhooks
- β³ π¬ Webhook Message Formats
- β³ π HTTPS Certificates & CA Bundles
- β³ π οΈ SSL Verification β the Global Setting
- β³ π Workflow & Webhook Pitfalls
- Issue trackers (Jira, Azure DevOps)
- π‘ Zabbix (monitoring)
- π¬ Microsoft Teams alerts
- π 3CX (phone system)
-
System
- β³ π οΈ Preferences β Developer Guide
- β³ π§Ή Maintenance
- β³ π Finding people in the Analysts list
- β³ πͺ When an analyst leaves
- β³ π οΈ System β Branding β Developer Guide
- β³ π©Ί Page health (D019) β Developer Guide
- β³ β Feature Bingo
- β³ π·οΈ Cost centres
- β³ π Chart of accounts
- β³ π· Photo Album
- β³ Demo Data
- β³ π οΈ Demo Data β Developer Guide
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ One company supporting another
- β³ π’ One board across every company
- β³ 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)
- What this is
-
π Bugs resolved
- β³ πͺ #326/#327 Form webhook Full record
- β³ π #325 Form PDF download failed
- β³ π Small fixes in 5.1.0
- β³ π CMDB relationships read backwards (5.1.0)
- β³ π #301 CSAT delay was never applied
- β³ π #281 Comments imported from Jira never arrived
- β³ π #288 A change failed to open with Enforce approvals on
- β³ π Long non-Latin articles never got an embedding
- β³ π« #280 Email lookups scanned the whole table
- β³ β #266 Dragging a task told nobody
- β³ π #255 Article previews showed HTML codes
- β³ π #252 A link to a Knowledge article did not open
- β³ π #254 PDFs could not print Polish
- β³ π #250 Clicking a folder left the open article on screen
- β³ π« #260 The dashboard cog did nothing
- β³ π« #248 A department rule never matched on four routes
- β³ π A directory account could be matched to someone else
- β³ π« #244 Reply went to the assigned analyst
- β³ π Mailbox sign-in was not checked
- β³ π Four weaknesses around signing in
- β³ π A lookup answer could name any record
- β³ π« #227 A mailbox could not be deleted
- β³ π« #226 A picture on a note could not be closed
- β³ π» #222 The Assets page never loaded in 4.3.0
- β³ βοΈ #214 A "contains" condition did not match capitals
- β³ βοΈ #216 A workflow email from a chosen mailbox always failed
- β³ π³ The Docker image was missing PHP extensions
- β³ π A failed DNS lookup read as a missing record
- β³ π A link could change data
- β³ π Access outlived its removal
- β³ π Knowledge articles could run scripts
- β³ π Knowledge writes ignored permissions
- β³ π Company boundaries (Oct 2026)
- β³ π Smaller gaps (Oct 2026)
- β³ π Escaped text could leave its attribute
- β³ π Task descriptions were not cleaned
- β³ π Task documents ignored company scope
- β³ π Repeating tasks ignored company scope
- β³ π¬ #183 Mailbox checks overlapped
- β³ π #188 Transfer lock shown off when unknown
- β³ β #184 Subtask names and Overdue
- β³ π§© #186 Teams: the buttons did nothing
- β³ π Text in a change could run script
- β³ π AI settings changed without the AI permission
- β³ πͺ #178 Deleting an analyst failed
- β³ π« A team with no departments showed 0 tickets
- β³ π Projects: adding a phase did nothing on Save
- β³ π Leavers could still sign in
- β³ πΌοΈ Logo and courses broke on Apache with PHP-FPM
- β³ π’ Chat tickets ignored your ticket numbering
- β³ π Dates shown as a dash, or in server time
- β³ π Assets β Users showed people from other companies
- β³ π Restricted analysts could read other modules' data
- β³ πΌοΈ Replies with a picture in the thread failed to send
- β³ π Reply attachments never reached the customer
- β³ π οΈ Outbound email attachments β Developer Guide
- β³ π A global SSO provider was missing from the portal
- β³ π Behind a proxy, the SSO redirect said http
- β³ βοΈ The portal tagline moved when you saved it
- β³ π¨ The portal settings screen forgot what you saved
- β³ π‘οΈ The approvals inbox said "Error" and nothing else
- β³ π A table's answers were missing from the PDF
- β³ β A single-select column let you tick every option
- β³ π The portal ignored a form's field widths
- β³ π The tasks board stopped taking clicks
- β³ ποΈ #121 The index list is out of date after upgrading
- β³ π #133 The calendar subscription was empty
- β³ π #131 Tasks always reopened on the board
- β³ π₯ #129 Every page returned HTTP 500 after upgrading
- β³ π³ #127 A PHP warning above the System page
- β³ π #126 Notes stamped with the server's clock
- β³ π Storing every date in UTC
- β³ πͺ The portal was down for everyone signed in
- β³ βοΈ #120 Workflow notes could never be written
- β³ βοΈ #123 Three errors when running Database Verification
- β³ π #122 The description box was a stub in the corner
- β³ π£ Demo data deleted real accounts
- β³ π #117 Sign-in redirected to the wrong address
- β³ π¨ #108 The priority dot was invisible
- β³ β±οΈ #116 Time logged from the right-click menu
- β³ π #114 API keys refused by our own guard
- β³ ποΈ #110 Assigning a task told nobody
- β³ πͺ #107 Signed out while still working
- β³ π #103 "Share with Requester" reached nobody
- β³ π #102 Search found nothing for hyphens
- β³ πͺ #101 Source code editor opened behind
- β³ βοΈ #88 Subtasks could not be ticked off
- β³ π» #84 Asset deep link selected nothing
- β³ π« #79 A new ticket arrived with no status
- β³ π§ #79 A ticket from email did not say so
- β³ π #78 Bell opened to nothing
- β³ π¬ #77 Mail only collected from Inbox
- β³ π #74 The default password could not be changed
- β³ π¦ #70 Renaming an impact level
- β³ π€ #67 App-only mailboxes could not send
- β³ π #45 Verify only ever worked for Microsoft
- β³ π #45 IMAP reported as not authenticated
- β³ βοΈ An email template stopped escaping itself
- β³ π The portal dashboard showed the wrong time
- β³ π’ The folder said 99 and the list showed 96