A customer reports a bug. Support writes a ticket, then pastes a GitHub link into a note and hopes. Three weeks later the customer asks for an update, the rep pings an engineer on Slack, the engineer looks it up, and the answer - "shipped last Tuesday" - was sitting in GitHub the whole time.
The information flow between support and engineering is one of the oldest unsolved problems in SaaS operations, and the tooling hasn't helped much:
- HubSpot's native Jira integration writes a small set of read-only Jira fields onto a ticket. You can't edit them, the sync can lag by hours, and because the issue never becomes a real object, there are no issue lists, no associations, and no issue-level reporting - and it's Jira, not GitHub.
- Generic sync platforms map issues onto objects you already have - a task, a deal, a ticket. Capable tools, but there's no dedicated issue object, no engineering-shaped properties like repository or PR state, and no UI built for the support-to-engineering handoff.
- Zapier and Make will happily copy fields one way per zap - and leave the two-way problem, including the infamous infinite update loop, entirely to you.
So we built what we actually wanted: Resonate Issues - GitHub Issues synced two-way into HubSpot as a first-class Issue object. It's live at github.resonatehq.com.
An Issue object, not fields on a ticket
On install, the app provisions a native Issue object in your portal. It appears next to Contacts, Deals, and Tickets with its own index page - and because it's a real object, everything HubSpot does with objects just works: filtered views, lists, workflows, reports, and associations.
| Title | Repository (synced path) | Status Category | URL | Object create date/time | Owner |
|---|---|---|---|---|---|
| Checkout 500 for EU Visa cards | acme/webapp | In progress | github.com/acme/webapp/is… | Today at 9:14 AM | No owner |
| SSO session expires after 15 min | acme/webapp | Open | github.com/acme/webapp/is… | Yesterday at 4:51 PM | No owner |
| Feature: bulk export to S3 | acme/api-server | Open | github.com/acme/api-serve… | Aug 4, 2026 3:56 PM | No owner |
| Add retry to payment webhook | acme/api-server | Done | github.com/acme/api-serve… | Aug 1, 2026 11:02 AM | No owner |
| Dark mode for customer portal | acme/webapp | Canceled | github.com/acme/webapp/is… | Jul 28, 2026 2:19 PM | No owner |
Each Issue carries the engineering context the CRM never had: repository, status (normalized to Open / In progress / Done / Canceled across trackers), labels, assignees, milestone, comment count, a direct link to the source - and the related pull request with its state, so support can see "PR merged" without asking anyone.
Issues associate with Tickets, Deals, Companies, Contacts, and Projects. That last part is what unlocks the reporting RevOps has been faking with spreadsheets: open bugs per customer, revenue waiting on engineering work, time from escalation to fix.
One click from ticket to GitHub
The Issues card sits on every Ticket record. Here it is - it's an interactive mock, so go ahead and click Create issue:
| Issue | Status | Repository | PR | Actions |
|---|---|---|---|---|
| Checkout 500 for EU Visa cards acme/webapp#214 | In progress | acme/webapp | PR open | PreviewUnlink |
| Add retry to payment webhook acme/api-server#188 | Done | acme/api-server | Merged | PreviewUnlink |
The panel prefills the title, description, and priority from the ticket. Pick a repository and create: the Issue record appears instantly, associated to the ticket, and shows Syncing to GitHub… - a few seconds later it flips to a live GitHub issue with its number and link. That's the real behavior, not marketing latency: sync is webhook-driven in both directions, with no scheduled polling.
Prefer to attach work that already exists? Link existing searches your portal's Issues by title or key. And Unlink removes only the association - it never deletes the Issue or the GitHub issue.
Projects get a repository and a board
HubSpot Projects get their own card: link a repository to the project, and manage its issues - list or board - without leaving the record:
The board is read-only by design: columns follow the issue status synchronized with the connected tracker, so what you see on the project is what engineering actually has in flight.
What syncs, exactly
Two-way sync earns trust by being precise about directions, so here is the honest map:
- Both directions - title, description, status (including the reopened / not-planned reason), labels, and assignees. Edit on either side; the other follows in seconds.
- GitHub → HubSpot - related PR and its state, comment count, author, milestone, repository and issue number, and source timestamps. Engineering facts stay engineering-owned.
- Comments - new GitHub comments become notes on the Issue record automatically. The reverse - posting HubSpot notes to GitHub - is an account-level toggle that ships off, because notes often hold private customer context. Comment mirroring is create-only: edits and deletes never propagate.
And the part that makes two-way sync safe to turn on: every write is fingerprinted and origin-tagged. When your own change echoes back through a webhook, the engine recognizes the fingerprint and drops it at the boundary. Changes converge in one hop, in either direction - the infinite loop that haunts DIY two-way sync is structurally impossible.
Automate on issue status
Because Issues are records, they enroll in workflows like anything else. The one every support team builds first - close the loop when the fix ships:
Set Ticket status to Fix shipped on associated tickets
Notify the ticket owner - time to tell the customer
An engineer closes an issue in GitHub. Seconds later the record flips to Done, the associated ticket moves, and the owner gets a nudge to deliver good news. Nobody checked a dashboard; nobody asked in Slack.
Works without GitHub, too
The Issue object is usable standalone: connect HubSpot, skip GitHub, and you have native issue tracking inside your CRM - with the same cards, associations, and workflows. Connect a tracker later and sync picks up from there. The object is provider-neutral by design, which is also how Jira and Linear will arrive: behind the same Issue object, no migration.
Set it up in four steps
- Connect GitHub at github.resonatehq.com - a per-repository GitHub App, so you grant exactly the repos you want and nothing else. (Optional - skip for standalone mode.)
- Choose repositories to sync, and a default repo for issues created from HubSpot.
- Connect HubSpot with one OAuth click - the Issue object and its properties are provisioned automatically.
- Import history: recent issues (last 30 days), everything, or start clean. Sync is two-way from that moment on.
One admin step inside HubSpot: cards aren't added to record views automatically. Open a Ticket record → Customize record → middle column → Add cards → add Issues. Once per portal.
The honest limits
GitHub is the only tracker today - Jira and Linear are the roadmap, not the present. Comment mirroring is create-only in both directions. Fields like PR state, milestone, and comment count are deliberately one-way from GitHub, because engineering facts should have one source of truth. And organization-owned repos need a one-time approval from a GitHub org owner. If any of this changes, this post will be updated.
Put engineering work inside your CRM - connect your first repo at github.resonatehq.com, or read more on the Resonate Issues app page.
Related reading
- DocsHub - our other app-object app: documents as first-class HubSpot records.
- Add an Approval Step to Any HubSpot Workflow - gate the risky automations your new Issue workflows might trigger.
- Lead Routing in HubSpot - the routing architecture that pairs well with escalation flows.
