DEV Community

Kal Wiggins
Kal Wiggins

Posted on • Originally published at dispatchtickets.com

Why I Stopped Using Traditional Helpdesks (And Built Support Into My App Instead)

Every helpdesk I've used follows the same pattern: it's a separate app. Your users email support@company.com, tickets land in Some Other Dashboard™, and your team context-switches between your product and your support tool all day.

It works. But it's not great.

What if support tickets were just... an API primitive? Like Stripe for payments or Twilio for SMS, but for support tickets?

The "We Have An API" Lie

Most helpdesks claim to have APIs. They do—technically. But there's a difference between "we bolted an API onto our app" and "the API is the product."

Here's how you can tell the difference:

Bolted-on API:

  • API is read-heavy (pull tickets into your system)
  • Webhooks are an afterthought
  • You still need their UI for most workflows
  • Authentication assumes you're the only consumer

API-first:

  • API is the primary interface
  • Webhooks are first-class citizens
  • Their UI is just a client consuming the same API you do
  • Multi-tenant by design

What This Looks Like in Practice

With an API-first ticketing system, creating a ticket is just a POST request:

curl -X POST https://api.dispatchtickets.com/v1/workspaces/ws_xxx/tickets \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Button not working on checkout page",
    "description": "User clicked Pay and nothing happened",
    "customer_email": "user@example.com",
    "priority": "high",
    "custom_fields": {
      "user_id": "usr_12345",
      "page_url": "/checkout",
      "browser": "Chrome 120",
      "error_log": "TypeError: undefined is not a function"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

See that custom_fields object? It takes any JSON. No predefined schema. No "please contact sales to add custom fields." Just pass whatever context is relevant.

The Cool Stuff This Enables

Once tickets are an API primitive, you can do things that traditional helpdesks make painful:

1. Automatic Ticket Creation from Errors

// In your error boundary or catch block
window.addEventListener('error', async (event) => {
  await fetch('/api/support/tickets', {
    method: 'POST',
    body: JSON.stringify({
      subject: `JS Error: ${event.message}`,
      description: event.error?.stack || 'No stack trace',
      custom_fields: {
        url: window.location.href,
        user_id: getCurrentUserId(),
        timestamp: new Date().toISOString()
      }
    })
  });
});
Enter fullscreen mode Exit fullscreen mode

Your support team sees the ticket before the user complains.

2. In-App Support That Actually Has Context

Instead of "please describe your issue," you can pre-fill everything:

function SupportButton({ user, currentPage }) {
  const openSupport = () => {
    openTicketModal({
      prefill: {
        customer_email: user.email,
        custom_fields: {
          user_id: user.id,
          plan: user.subscription.plan,
          page: currentPage,
          recent_actions: user.activityLog.slice(-10)
        }
      }
    });
  };

  return <button onClick={openSupport}>Get Help</button>;
}
Enter fullscreen mode Exit fullscreen mode

No more "what's your account email?" No more "can you send a screenshot?" The context is already there.

3. Build Support Into Your Admin Dashboard

Why make your team learn another app?

// In your existing admin panel
function CustomerDetail({ customerId }) {
  const { data: tickets } = useQuery(
    ['tickets', customerId],
    () => fetchTickets({ customer_id: customerId })
  );

  return (
    <div>
      <CustomerInfo id={customerId} />
      <OrderHistory id={customerId} />
      <SupportTickets tickets={tickets} /> {/* Same dashboard */}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Your ops team sees customer info, orders, and support tickets in one place. No tab switching.

4. Webhooks for Everything

When a ticket is created, updated, or resolved—you get a webhook. Build whatever you want:

// Your webhook handler
app.post('/webhooks/tickets', (req, res) => {
  const { event, ticket } = req.body;

  if (event === 'ticket.created' && ticket.priority === 'urgent') {
    // Page on-call engineer
    pagerDuty.trigger({
      summary: ticket.subject,
      source: 'support-ticket',
      severity: 'high'
    });
  }

  if (event === 'ticket.resolved') {
    // Update your CRM
    crm.updateContact(ticket.customer_email, {
      last_support_interaction: new Date(),
      tickets_resolved: increment(1)
    });
  }

  res.sendStatus(200);
});
Enter fullscreen mode Exit fullscreen mode

The Pricing Thing

Traditional helpdesks charge per seat. Five agents? Five seats. But here's the thing—in a modern SaaS, everyone touches support sometimes:

  • Engineers triage bugs
  • PMs review feature requests
  • Founders reply to key accounts

Per-seat pricing punishes this. You either pay $79/month for someone who handles 3 tickets, or you create workarounds (shared logins, forwarding emails, Slack threads about tickets).

API-first systems tend toward usage-based pricing. Pay for tickets, not seats. Everyone can have access.

When Not to Use API-First

To be fair, API-first ticketing isn't for everyone:

  • Non-technical teams: If no one can write code, you need a full UI out of the box
  • Simple needs: If email-only support with 1-2 agents covers you, a traditional helpdesk is fine
  • Existing investment: If you've already built complex workflows in Zendesk, migration has a cost

But if you're building a SaaS product and you have developers on the team? There's no reason your support system should be less flexible than everything else in your stack.

TL;DR

  • Traditional helpdesks are apps with APIs bolted on
  • API-first ticketing means tickets are the primitive—build whatever you want
  • You can embed support in your product, not around it
  • Custom fields take any JSON (no schema limits)
  • Webhooks let you integrate with everything
  • Usage-based pricing means your whole team can have access

I'm building Dispatch Tickets—an API-first ticketing system designed for developers. If you're interested, we're doing early access right now.

Top comments (0)