Skip to content

Raise issues from your support tool

When a customer reports a bug, the check it breaks should go red in front of the people testing the release — not wait in a ticket queue until someone thinks to copy it over.

The shape of it

  1. An agent tags the ticket — login-broken, card-declined — the way they already triage.
  2. The helpdesk calls a small function of yours with the ticket.
  3. The function maps the tag to a check ref and raises an issue against it, with the customer as the reporter.
  4. The check fails on that platform in qarunbook until the issue is fixed and a tester confirms it.

Every helpdesk worth using — Zendesk, Intercom, Help Scout, Freshdesk, Front — can call a URL when a ticket is tagged. The function in between is the only thing you write.

Make a key for it

Under API, create a tester key named after the helpdesk, scoped to the apps customers can report against. Tester is enough to raise issues and no more: the helpdesk never needs to fix one. Put it in the function's environment as QARUNBOOK_KEY.

The handler

api/support-webhook.js
// api/support-webhook.js — a serverless function your helpdesk calls
// when an agent tags a ticket "bug".
const CHECK_FOR_TAG = {
  "login-broken": "AUTH-01",
  "reset-email-missing": "AUTH-04",
  "card-declined": "PAY-02",
};

export default async function handler(req, res) {
  const ticket = req.body.ticket;
  const tag = ticket.tags.find((t) => t in CHECK_FOR_TAG);
  if (!tag) return res.status(204).end(); // not one we map — nothing to do

  const r = await fetch("https://qarunbook.com/api/v1/issues", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.QARUNBOOK_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      app: "Checkout",
      check: CHECK_FOR_TAG[tag],
      text: `${ticket.subject}\n\n${ticket.description}\n\nTicket: ${ticket.url}`,
      platforms: ticket.platform ? [ticket.platform] : undefined,
      reporter: { name: ticket.requester.name, email: ticket.requester.email },
    }),
  });
  const { data, error } = await r.json();
  if (error) return res.status(502).json({ error: error.message });

  // Keep the issue id on the ticket, so the fix can be matched back later.
  return res.status(200).json({ qarunbook_issue: data.id });
}

Map tags to refs, not ids. Refs like AUTH-01 are what your testers already say out loud, they survive a plan being re-imported, and a support lead can read the mapping.

In the runbook the issue reads Ada Lovelace via API, so it is plain it came from a customer and not a tester. Her email is stored with the issue for whoever picks it up.

Ten tickets, one bug

A bad release produces the same ticket many times, and ten identical issues on one check help nobody. Before raising, look for one already open on that check and add to the ticket instead:

Check first
const open = await fetch(
  "https://qarunbook.com/api/v1/issues?app=Checkout&check=AUTH-01&status=open",
  { headers: { Authorization: `Bearer ${process.env.QARUNBOOK_KEY}` } },
).then((r) => r.json());

if (open.data.length) return res.status(200).json({ qarunbook_issue: open.data[0].id });

Closing the loop

Keep the issue id on the ticket. When the issue reads fixed, the customer can hear about it — and when the check is back to passed, you know somebody has actually seen it work.

Tell the customer
// When the issue is fixed, tell the customer. Poll, or run this on a schedule.
const r = await fetch(
  `https://qarunbook.com/api/v1/issues/${issueId}`,
  { headers: { Authorization: `Bearer ${process.env.QARUNBOOK_KEY}` } },
);
const { data } = await r.json();
if (data.status === "fixed") {
  await helpdesk.reply(ticketId, "Good news — a fix for this is out and being checked.");
}

Something unclear or missing? Write to hello@qarunbook.com.