A helpdesk token is proven by its Last Used column, not by the code that sends it
Decided
When /support returned not filed (helpdesk returned HTTP 401 — Can't find User for Token), the request shape was not changed. The token was replaced. lib/helpdesk.ts is unmodified by this fix.
Why that ordering was not obvious. A 401 from an API invites you to re-read your own request, and there was plenty to re-read: Authorization: Token token=… is an unusual header format, customer_id: "guess:<email>" is a Zammad-specific syntax, tags is a comma-joined string rather than an array, and priority_id is a numeric mapping. Any of those could plausibly produce an authentication error in a vendor that validated the whole envelope before the credential. The temptation is to start editing.
Two pieces of evidence made editing the wrong move. First, a probe with the byte-identical payload under session authentication returned 201 Created with ticket 87003 — so every field in the request was acceptable to this instance, and only the credential differed. Second, and more cheaply, Zammad's Token Access page has a Last Used column, and for the token named novelsystems-website it was *empty* three hours and forty-seven minutes after the token was created, during which the production site had attempted to file at least one ticket. A token that has never authenticated a single request is not a token that is being rejected for the shape of the request carrying it. It is a token that is not the value the caller is sending.
The general rule. Prefer the evidence the vendor keeps about the credential over the evidence you can construct about your own code. "Last Used is blank" distinguishes *wrong key* from *wrong request* in one glance; a payload diff against the vendor's documentation cannot, because a correct payload and an incorrect one fail identically at the auth layer.
What replaced it. A fresh personal access token, ns-site-2, scoped to ticket.agent and nothing else — the minimum that can create a ticket in a group. No expiry is set, which is a deliberate and slightly uncomfortable choice: an expiring token turns a silent 401 into a scheduled one, and this deployment has no alerting that would catch either. The mitigation is the alarm below, not the expiry date.
What would make this wrong. If lib/helpdesk.ts is ever pointed at a Freshdesk account, the header format changes to HTTP Basic and this entry's reasoning about the header being innocent does not transfer. Re-derive it.