A REST layer and staff token portal you drop onto an existing HESK 3.7.x help desk. Tokens are bound to HESK staff accounts. The help-desk source is not modified.
POST /v1/auth/token) for automation/openapi.json rewritten for this install’s public URL and branding/health (no auth)q, archivedformat: auto | plain | html | markdown; optional message_html)<2026-08-19T21:58:12.969Z> stay visible (not treated as HTML tags). Leftover text newlines become line breaks in the HESK staff UIPOST /v1/tickets/{id}/notes with files, or POST /v1/tickets/{id}/notes/{noteId}/attachmentsnotify: true|false)GET /v1/attachments/limitsGET /v1/privilegesEvery install is meant to be yours:
| Area | How |
|---|---|
| HESK path and public URLs | config.local.php or installer flags |
| Portal name and vendor footer | branding |
| REST prefix | api_prefix |
| Token prefix, TTL, max per user | token |
| CORS origins | cors |
| Rate limits | rate_limit |
| Pagination | pagination |
| Logging / debug | log, debug |
| Table prefix | Inherited from HESK db_pfix |
| TLS / vhost / PHP-FPM | Sample nginx config you copy and edit |
Full knob list on the install page →
The package can poll Tactical Data Concepts for a newer zip:
/updates): shows this install’s version, the latest on TDC.com, and a link to upgrade instructions when a newer package exists. Admins can set check / notify / auto-install thereGET /v1/updates or php bin/check-updates.phpconfig/config.local.php, hesk-api-creds.txt, or storage/Upgrade instructions → · Config knobs on the install page →
A second hostname (for example api.help.example.com) with its document root
on hesk-api/public, talking to the same MySQL database as HESK.
Staff keep using HESK. Automations and other hosts use the API.
/tokens) shows the same installed vs TDC comparison, with an upgrade-instructions link when behindoff / notify-by-ticket / auto-install) persisted in storage/updates/settings.json (kept across package replace)PATCH /v1/updates/settings for the same knobs; channel upgrade_url (defaults to {channel}/upgrade.html)GET /v1/updates, php bin/check-updates.php)updates.mode = off). notify opens a HESK ticket to a configured owner and/or category with zip URL, SHA-256, and install stepsmode=auto and allow_auto_install, or an admin POST /v1/updates/apply with confirm=APPLY): HTTPS only, host allow-list, SHA-256 required, zip layout/symlink/traversal checks, backup, never overwrite config.local.php / hesk-api-creds.txt / storage/version.json when the channel publishes it; falls back to VERSION + hesk-api-{version}.zip + .sha256allow_downgrade + force; refuses unsigned/mismatched zipsmessage bodies are stored as HTML the HESK staff UI can renderformat: auto (default), plain, html, markdown (aliases text, md / gfm)message_html is sanitized as HTML (same whitelist as format=html)auto no longer treats log timestamps such as <2026-08-19T21:58:12.969Z> as HTML (the old strip_tags check skipped nl2br and produced a wall of text)script / style / event handlers / javascript: URLs, and converts leftover text newlines to <br>|---|---| separator, alignment :--- / :---: / ---:, inline markdown in cells)nl2brtime_worked on POST /v1/tickets/{id}/replies)PATCH /v1/tickets/{id} (time_worked / time_worked_add)time_workedbin/repair-ticket-history.php rewrites older API history rows into that formattachments[])POST /v1/tickets/{id}/notes/{noteId}/attachments adds files to an existing noteGET /v1/tickets/{id}/notes includes attachments on each noteFirst public, transportable package.
config.local.php, applies schema with the live HESK table prefix, optional utf8mb4 conversion, optional bootstrap tokenHESK_PATH / HESK_URL / HESK_API_URL env fallbackshesk_settings