Skip to content

Add HappyFox skill for help desk ticket management#197

Open
jpshackelford wants to merge 7 commits into
mainfrom
add-happyfox-skill
Open

Add HappyFox skill for help desk ticket management#197
jpshackelford wants to merge 7 commits into
mainfrom
add-happyfox-skill

Conversation

@jpshackelford

Copy link
Copy Markdown
Member

Summary

This PR adds a new skill for interacting with the HappyFox help desk API, enabling ticket creation and management operations.

Features

The HappyFox skill supports:

  • Create Tickets: Create new support tickets with contacts, categories, priorities, and custom fields
  • Update Tickets: Add staff replies, change status, priority, assignee, and tags
  • Private Notes: Add internal notes visible only to staff
  • Query Tickets: List, filter, and search tickets by various criteria (status, assignee, date, contact, etc.)
  • Tag Management: Add and remove tags from tickets
  • Category Management: Move tickets between categories
  • Custom Fields: Full support for ticket and contact custom fields

Required Environment Variables

  • HAPPYFOX_API_KEY: HappyFox API key
  • HAPPYFOX_AUTH_CODE: HappyFox auth code
  • HAPPYFOX_SUBDOMAIN: HappyFox account subdomain (e.g., acme for acme.happyfox.com)

Documentation Sources

The skill is based on the official HappyFox API documentation:

Triggers

The skill is activated by:

  • happyfox
  • help desk
  • support ticket

Files Added

  • skills/happyfox/SKILL.md - Full skill documentation with API examples
  • skills/happyfox/README.md - Overview and quick reference

This PR was created by an AI assistant (OpenHands) on behalf of the user.

@jpshackelford can click here to continue refining the PR

This skill enables interaction with the HappyFox help desk API for:
- Creating and updating support tickets
- Adding staff replies and private notes
- Managing ticket status, priority, and assignee
- Querying and filtering tickets
- Working with custom fields
- Moving tickets between categories

Requires HAPPYFOX_API_KEY, HAPPYFOX_AUTH_CODE, and HAPPYFOX_SUBDOMAIN
environment variables.

Co-authored-by: openhands <openhands@all-hands.dev>
@jpshackelford jpshackelford marked this pull request as ready for review April 22, 2026 20:00

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Acceptable - Well-structured skill with comprehensive documentation, but missing required marketplace entry.

Note: Review body kept brief per instructions. See inline comments for specific issues.

Comment thread skills/happyfox/SKILL.md
@@ -0,0 +1,370 @@
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical - Missing Marketplace Entry: This skill must be added to marketplaces/openhands-extensions.json or CI will fail.

According to AGENTS.md:

The test suite expects every directory under skills/ to be listed in a marketplace. If you add a new skill, update the appropriate marketplace file or CI will fail.

Add an entry alphabetically between gitlab and iterate with this structure:

{
  "name": "happyfox",
  "source": "./skills/happyfox",
  "description": "Interact with HappyFox help desk - create tickets, add updates, manage ticket status, and query tickets using the HappyFox REST API.",
  "category": "integration",
  "keywords": [
    "happyfox",
    "help desk",
    "support",
    "ticket",
    "api"
  ]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine we should address this

Comment thread skills/happyfox/SKILL.md

# HappyFox

<IMPORTANT>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Good Practice: Checking environment variables before use is the right approach. Clear, actionable guidance for users.

Comment thread skills/happyfox/SKILL.md Outdated
- Auth Code: `$HAPPYFOX_AUTH_CODE`
- Subdomain: Your HappyFox account name (e.g., `acme` for `acme.happyfox.com`)

> **Note**: If your HappyFox account is hosted in EU, use `<subdomain>.happyfox.net` instead of `<subdomain>.happyfox.com`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Consider mentioning what determines EU vs US hosting. Users might not know which domain to use without checking their HappyFox admin panel.

Suggested addition:

> **Note**: If your HappyFox account is hosted in EU, use `<subdomain>.happyfox.net` instead of `<subdomain>.happyfox.com`. Check your HappyFox URL in your browser or contact your admin if unsure.

Comment thread skills/happyfox/README.md Outdated

- `HAPPYFOX_API_KEY`: Your HappyFox API key
- `HAPPYFOX_AUTH_CODE`: Your HappyFox auth code
- `HAPPYFOX_SUBDOMAIN`: Your HappyFox account subdomain (e.g., `acme` for `acme.happyfox.com`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Acceptable: The <IMPORTANT> block provides clear, practical guidance. The instruction to verify environment variables before operations follows good defensive programming practices.

- Add credential detection script that checks for HFOX_* or HAPPYFOX_* variables
- HFOX prefix supports custom domains via HFOX_BASE_URL (full URL)
- HAPPYFOX prefix uses HAPPYFOX_SUBDOMAIN for standard happyfox.com domains
- Unified HF_* variables used in all API examples after detection
- Updated README.md to document both configuration options

Co-authored-by: openhands <openhands@all-hands.dev>
…havior notes

- Add IMPORTANT warning that /staff_pvtnote/ is the ONLY way to create private notes
- Clarify that /staff_update/ with visible_only_staff or private params does NOT create private notes
- Document that update_customer: false only prevents email, reply is still visible in portal
- Add note about attachment URL expiration (signed S3 URLs ~15 min)
- Document message_type field: 'p' for private notes, null for regular updates
- Add text field option for private notes (in addition to html)

Co-authored-by: openhands <openhands@all-hands.dev>

@ak684 ak684 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall looks good but let's get tests passing and I'd personally prefer less broad common word triggers (or maybe we leverage / command triggers instead to increase the intention threshold)

Comment thread skills/happyfox/README.md
Comment on lines +10 to +11
- `help desk`
- `support ticket`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my first time reviewing these repo. Is it in fact that case that this skill directory gets pulled into every agent conversation on our SaaS / OHE instances by default? If so I think "help desk" and "support ticket" are too broad of triggers. Other customers may have help desk flows and be using Zendesk or Intencom and not HappyFox.

Comment thread skills/happyfox/SKILL.md
@@ -0,0 +1,370 @@
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine we should address this

Comment thread skills/happyfox/SKILL.md
Comment on lines +6 to +7
- help desk
- support ticket

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto from above

Three documentation additions, all empirically verified against a live
HappyFox v1.1 instance:

1. Write-safety: avoid duplicate writes
   HappyFox v1.1 has no edit/delete endpoint for individual updates or
   private notes — only whole-ticket deletion. There is no 'undo' for
   any write. Documents the right reflex on an ambiguous curl response
   (check exit code, GET-verify before any retry) and provides the
   canonical pre/post-state bash pattern. Lists the probed-and-confirmed
   dead-end delete/edit paths so future agents don't repeat the probes.

2. Endpoints that do NOT exist on v1.1
   Quick reference table of integration / linked-object / linked-ticket
   paths that all return 404. Native integration metadata (e.g. the
   HappyFox<->Linear link) is not exposed via the API; cross-link
   enumeration must happen on the destination system.

3. Message Formatting: HTML Only, No Markdown
   Rendering matrix showing which HTML tags render (`<p>`, `<br>`,
   `<a href>`, `<strong>`, `<em>`, lists) vs which Markdown syntax
   appears as literal text (`##`, `**`, `[text](url)`, code spans).
   Cites HappyFox's 'Markdown Support while Adding Ticket Replies'
   release note to clarify that feature is a compose-box typing shortcut
   for human agents only — the API still treats `html` as HTML and
   `text` as plain text, never markdown.

4. Add Private Note (strengthened)
   Adds the `message.message_type` verification step: 'p' means private
   note, null means customer-visible. If a private-note POST ends up
   with `message_type: null`, internal content has leaked to the
   customer and there is no API to fix it.

These rules were derived during a real cross-link backfill session on a
live OpenHands HappyFox instance and prevented further duplicate writes
after the first incident.

Co-authored-by: openhands <openhands@all-hands.dev>

Copy link
Copy Markdown
Member Author

Pushed a9e6551 — three additions derived from a real cross-link backfill session on a live HappyFox v1.1 instance:

  • Write-safety: avoid duplicate writes — HappyFox has no edit/delete API for individual notes; documents the GET-verify-before-retry reflex and the canonical pre/post-state bash pattern. Prevents the kind of accidental duplicate-post that triggered this work.
  • Endpoints that do NOT exist on v1.1 — quick reference table of integration / linked-object paths that all 404 so future agents don't repeat the probes.
  • Message Formatting: HTML Only, No Markdown — rendering matrix (<p>/<a>/<strong> render; ##/**/[text](url) appear as literal text). Cites HappyFox's "Markdown Support while Adding Ticket Replies" release note to clarify that feature is a compose-box typing shortcut only — the API still treats html as HTML and text as plain text.
  • Add Private Note (strengthened) — adds message_type post-write verification so private-note leaks (/staff_update/ vs /staff_pvtnote/) can be detected immediately.

Cross-referenced by OpenHands/extensions-private PR #4 (sync skill back-link write) which depends on these rules.

This comment was posted by an AI agent (OpenHands) on behalf of John-Mason Shackelford.

The "Create a Ticket" section did not mention custom fields at all.
HappyFox v1.1 accepts ticket custom fields on create as form-field
keys named 't-cf-<id>' at the top level of the JSON payload, NOT
under a 'custom_fields' object. Discovered empirically while filing
a ticket on a live instance — the first attempt with 'custom_fields_1'
returned:

  {"error":[{"field":"t-cf-1","errors":["This field is required"]}]}

The 422-style error response helpfully names the exact field key
the API expects, so the next attempt with 't-cf-1: <value>' works.

Adds:
- Optional-fields entry for 't-cf-<id>'.
- A worked POST example with both a choice (Product Type) and a text
  (Conversation URL) custom field.
- The exact failure shape so future agents recognize it.
- Pointer to the "List Ticket Custom Fields" lookup section
  (GET /ticket_custom_fields/) and to the per-ticket
  custom_fields[] array as the two discovery paths.

Instance-specific custom-field IDs and choice tables stay in the
private 'openhands-happyfox' skill (extensions-private PR #2) — this
commit only documents the generic API convention.

Co-authored-by: openhands <openhands@all-hands.dev>

Copy link
Copy Markdown
Member Author

Pushed 597e227 — adds the t-cf-<id> custom-field convention to the "Create a Ticket" section.

The section previously didn't mention custom fields at all. Discovered the correct field-name shape empirically when a real ticket-create call returned:

{"error":[{"field":"t-cf-1","errors":["This field is required"]}]}

The 422 names the exact expected key, so the right reflex is to read the response. The commit adds a worked POST example with both a choice and a text custom field, the failure shape so future agents recognize it, and pointers to the existing /ticket_custom_fields/ lookup section + the per-ticket custom_fields[] array for discovering IDs.

Instance-specific custom-field IDs and choice tables remain in the private companion skill — only the API convention is documented here.

This comment was posted by an AI agent (OpenHands) on behalf of John-Mason Shackelford.

The skill previously documented attachment *reads* (signed S3 URLs in GET
responses) but not attachment *uploads*. Add a section covering:

- The docs-backed contract from /kb/article/1039-tickets-endpoint/
  (field: 'attachments' plural, multipart/form-data, 25 MB combined cap,
  no file-type restrictions, UTF-8 encoding default)
- Endpoints that accept attachments (POST /tickets/, /staff_update/,
  /staff_pvtnote/) plus the separate /ticket-inline-attachment/ for inline
  images embedded in the html field
- A curl recipe (preferred) showing the multi-value form-field syntax
- A Python stdlib (urllib) recipe as a fallback
- A verification pattern that reads back .updates[-1].message.attachments
- A caveat documenting an empirically-reproducible curl quirk: 'curl -F
  attachments=@/path/file' fails with '(26) Failed to open/read local
  data from file/application' on small readable files in some
  containerized environments (verified with curl 8.14.1). Documented as
  an empirical workaround so future agents fall through to Python
  immediately rather than wasting cycles retrying curl.

Co-authored-by: openhands <openhands@all-hands.dev>
…-op audit entry

Two empirically-verified additions to the 'Update Ticket Properties Only'
section:

1. Custom fields can be updated on existing tickets via /staff_update/
   using the same t-cf-<id> form-field convention as ticket creation.
   Text fields take raw strings; choice fields take the numeric choice id.

2. Every /staff_update/ POST creates an audit entry, even when the
   payload contains no message body and no tracked-change field
   (status, priority, assignee, tags, due_date). Property-only and
   custom-field-only writes therefore leave a 'message: null' row with
   all *_change fields null (custom_field_change is never populated by
   the API for custom-field writes). The row is invisible in the
   customer portal, sends no email, but does show in the staff timeline
   and bumps last_updated_at. Batch multiple property/custom-field
   writes into one call to avoid stacking no-op rows.

Co-authored-by: openhands <openhands@all-hands.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants