Helpdesk · Developers
Build on Helpdesk
React to ticket events from your plugin, script the inbox with a staff session, give AI agents the core ticket actions, or theme the support pages.
What you can build
Plugins that react to tickets
justflows.helpdesk.ticket.* events: created, replied, noted, status changed, escalated, or a name your own automation emits.Staff tools
AI agents
helpdesk_* MCP tools cover the core ticket actions. Each tool description warns the agent that ticket text is written by customers.Themes and support pages
Base URL
https://your-site.example/api/helpdeskThe older /ext/justflows.helpdesk address also works. Paths in this reference are relative to the base URL.
Who can call a route
| Kind | Who | How |
|---|---|---|
staff | Staff with a Helpdesk capability | The jf_session cookie and the capability on each route. Writes send the CSRF token as x-csrf-token. |
portal | Customers and guests | A signed-in requester, or a guest with the private token from the ticket email (only its hash is stored). Writes skip the CSRF token but must come from a page on this site: an Origin that does not match the host is refused. |
const HELPDESK = "https://your-site.example/api/helpdesk";
const csrf = document.cookie.match(/(?:^|; )jf_csrf=([^;]+)/)?.[1];
// Unassigned urgent tickets, then take the first one.
const { tickets } = await (await fetch(`${HELPDESK}/tickets?priority=urgent&assignee=none`, { credentials: "include" })).json();
await fetch(`${HELPDESK}/tickets/${tickets[0].id}/replies`, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json", "x-csrf-token": csrf },
body: JSON.stringify({ kind: "internal_note", body: "Taking this one." }),
});Errors
Failures use one envelope with a stable code and a message you can show:
{ "error": { "code": "invalid_subject", "message": "Enter a subject of at least 3 characters." } }| Code | Meaning |
|---|---|
forbidden | The session lacks the capability. |
not_found | No such ticket, or one you cannot open. Both look the same on the portal. |
invalid_subject, invalid_status, invalid_priority, invalid_type, invalid_visibility | A field has a value Helpdesk does not accept. |
feature_disabled | A plan limit or setting has turned the feature off for this site, such as public tickets or sensitive messages. |
origin | A portal write came from another site. |
sign_in | The route needs a signed-in visitor. |
rejected_file, files_unavailable | An upload was refused, or the site has no file storage. |
secure_unavailable | Sensitive messages need the encryption key, which is missing. |
Rate limits
| Routes | Limit |
|---|---|
| Staff reads | 120 a minute |
| Staff writes | 60 a minute |
| Portal reads | 60 a minute |
| Portal writes: new ticket, reply, find, status, rating, uploads | 10 per 10 minutes |
| Customer reveal of a sensitive message | 30 per 10 minutes |
Files and sensitive data
Uploads send the raw file as the request body (up to 25 MB) with ?filename=. Helpdesk checks the real type, refuses executables, strips JPEG metadata, and stores the file privately. Add sensitive=1 to encrypt it. Downloads use the signed link the ticket view returns.
Sensitive messages and files are encrypted with JUSTFLOWS_HELPDESK_KEK, a 32-byte key Justflows creates in the server .env and never stores in the database. Staff reveal them with helpdesk.secrets:reveal, requesters on their own ticket, and every reveal is recorded. They are left out of email, the public archive, and reply suggestions.
Blocks
Activation publishes the support pages built from these blocks. Use them on any page, or style them from your theme.
| Block | What it shows |
|---|---|
justflows.helpdesk.new | New support ticket: the request form. |
justflows.helpdesk.my | My tickets, for a signed-in visitor. |
justflows.helpdesk.public | Public tickets, with search. |
justflows.helpdesk.ticket | Support ticket: one request and its thread. |
justflows.helpdesk.find | Find a request by number and email. |
justflows.helpdesk.support | Open support: a button that opens the popup. |
justflows.helpdesk.order | Help with an order: starts a ticket about one Shop order. |
justflows.helpdesk.product | Ask about a product: starts a ticket about one Shop product. |
justflows.helpdesk.request | Request sent: the confirmation after sending. |