Jira · recipe

Turn App Store and Google Play reviews into Jira issues

There is no native Jira destination. Two setups work today: a signed webhook destination with a small receiver that calls the Jira API, or an AI agent that reads reviews over MCP and files the Jira issue with its own Jira access.

Webhooks: Enterprise plan · MCP: every plan · 14-day free trial

What works today

Webhook + receiver (automatic)
Review Expert POSTs each matching review as signed JSON. Your receiver verifies the signature and creates the Jira issue.
MCP + agent (on demand)
An agent searches reviews with the Review Expert MCP server and files Jira issues through its own Jira connection.
Only the reviews you want
Webhook destinations filter by minimum rating, maximum rating and keywords.

Option 1: webhook destination and a receiver

  1. 1

    Deploy the receiver

    Host the code below anywhere that serves HTTPS (a serverless function is enough). It needs a Jira token with permission to create issues.
  2. 2

    Add a webhook destination

    In Review Expert open Automation → Manage destinations, choose Webhook and paste your receiver URL. Copy the signing secret shown once after you save it into the receiver's REVIEWEXPERT_WEBHOOK_SECRET.
  3. 3

    Set filters and send a test

    For bug triage, a common filter is ratings 1 to 2 or keywords such as "crash" and "login". Send a test notification (it has "test": true) to check the Jira issue is created.
Headers on every requestSigned with your destination's secret
X-ReviewExpert-Timestamp: <unix seconds>
X-ReviewExpert-Signature: v1=<hex HMAC-SHA256(secret, "<timestamp>.<raw body>")>
X-ReviewExpert-Event: review.created | review.negative | review.positive
X-ReviewExpert-Delivery: <stable id per destination and review, repeated on retries>
Example body (fields may be added; ignore unknown ones)POST, Content-Type: application/json
{
  "delivery_id": "…",
  "event": "review.negative",
  "events": ["review.created", "review.negative"],
  "created_at": "2026-10-13T08:00:00.000Z",
  "test": false,
  "review": {
    "id": "3f9c2b1e-…",
    "rating": 2,
    "title": "Sync broke",
    "content": "Sync stopped working after the latest update.",
    "author_name": "Alex M.",
    "posted_at": "2026-10-13T07:51:00.000Z",
    "sentiment": "negative",
    "app_version": "4.2.0",
    "country": "US",
    "url": "https://…"
  },
  "property": { "id": "8a71d0c4-…", "name": "Acme Notes", "type": "google-play", "external_id": "com.acme.notes", "icon_url": null, "store_url": "https://…" },
  "links": { "review_url": "https://review.expert/admin/…" }
}
Receiver (Node.js 18+, no dependencies)Verify the signature, then create the Jira issue
import crypto from "node:crypto";
import http from "node:http";

const SECRET = process.env.REVIEWEXPERT_WEBHOOK_SECRET;
const seen = new Set(); // use a database in production

function verify(raw, headers) {
  const ts = Number(headers["x-reviewexpert-timestamp"]);
  const sig = String(headers["x-reviewexpert-signature"] || "");
  if (!Number.isInteger(ts) || Math.abs(Date.now() / 1000 - ts) > 300) return false;
  const expected = "v1=" + crypto.createHmac("sha256", SECRET).update(ts + "." + raw).digest("hex");
  return sig.split(",").some((s) => s.trim().length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(s.trim()), Buffer.from(expected)));
}

// Jira Cloud REST API v3. JIRA_TOKEN is an Atlassian API token for JIRA_EMAIL.
async function createIssue(summary, text) {
  const auth = Buffer.from(`${process.env.JIRA_EMAIL}:${process.env.JIRA_TOKEN}`).toString("base64");
  const res = await fetch(`https://${process.env.JIRA_SITE}.atlassian.net/rest/api/3/issue`, {
    method: "POST",
    headers: { Authorization: `Basic ${auth}`, "Content-Type": "application/json", Accept: "application/json" },
    body: JSON.stringify({
      fields: {
        project: { key: process.env.JIRA_PROJECT }, // e.g. "MOB"
        issuetype: { name: "Bug" },
        summary: summary.slice(0, 250),
        labels: ["app-review"],
        description: {
          type: "doc",
          version: 1,
          content: [{ type: "paragraph", content: [{ type: "text", text }] }],
        },
      },
    }),
  });
  return res.ok;
}

http.createServer(async (req, res) => {
  let raw = "";
  for await (const chunk of req) raw += chunk;
  if (req.method !== "POST" || !verify(raw, req.headers)) return res.writeHead(401).end();
  const delivery = req.headers["x-reviewexpert-delivery"];
  if (seen.has(delivery)) return res.writeHead(200).end();
  const { review, property, links } = JSON.parse(raw);
  const title = `[${property.name}] ${review.rating}★ ${review.title ?? (review.content ?? "").slice(0, 60)}`;
  const body = [
    review.content ?? "(no text)",
    "",
    `Rating: ${review.rating}/5 · Version: ${review.app_version ?? "n/a"} · Country: ${review.country ?? "n/a"}`,
    `Review in Review Expert: ${links.review_url}`,
  ].join("\n");
  const ok = await createIssue(title, body);
  if (ok) seen.add(delivery);
  res.writeHead(ok ? 200 : 502).end(); // a non-2xx makes Review Expert retry
}).listen(process.env.PORT || 8080);

Set JIRA_SITE (the part before .atlassian.net), JIRA_EMAIL, JIRA_TOKEN (an Atlassian API token) and JIRA_PROJECT. Change issuetype if your project has no “Bug” type. The description uses Atlassian Document Format, which Jira Cloud's v3 API requires.

Option 2: an agent with MCP

The Review Expert MCP server is live on every plan. Connect it to an agent (for example in Claude, ChatGPT, Cursor or VS Code) that also has a Jira connection, then ask something like: “Find 1–2 star Google Play reviews from the last 7 days that mention crashes, group them by problem and open one Jira issue per problem with links to the reviews.”

The agent uses tools such as search_reviews, get_app_reviews and get_review to read reviews; creating the Jira issue is done by the agent's own Jira tooling, not by Review Expert. See the tool reference.

Good practice

Always verify the signature
Reject requests with a bad signature or a timestamp older than 5 minutes.
De-duplicate on delivery id
Retries repeat X-ReviewExpert-Delivery. Store it so one review never becomes two Jira issues.
Least-privilege token
Give the receiver a Jira token that can only create issues in the target project.
Filter before you file
Use rating and keyword filters so only actionable reviews reach the tracker.

Plans

Webhook destinations are on Enterprise; the MCP server is on every plan.
Prices in USD. Every plan starts with a 14-day free trial and can be cancelled anytime. Need something custom? Email contact@review.expert.
DestinationStarterProEnterprise
Price (monthly / billed annually)$49 / $39 per month$149 / $119 per month$399 / $319 per month
Connected apps2410
Team members515Unlimited
Slack✓✓✓
Linear✓✓✓
Microsoft Teams✗✓✓
Zendesk✗✓✓
Webhooks✗✗✓
Zapier✗Coming soonComing soon
Filters: min rating, max rating, keywords✓✓✓
No native Jira destination
Review Expert does not connect to Jira directly. These recipes use the webhook destination and the MCP server, which are live today.

Frequently asked questions

Send the reviews that matter to Jira

Try Enterprise free for 14 days, set up a webhook destination and point it at your receiver.