# How to Send a New Relic Alert to a Shared Phone Room

> Route one selected New Relic issue through an authenticated relay, then send fixed activated and closed signals to a private PingRoom Room.

- Published: 2026-11-01
- Author: PingRoom
- Category: Developers
- Topics: New Relic alert push notification, New Relic webhook phone alert, shared monitoring alerts, webhook push notifications
- Canonical: https://pingroom.io/blog/new-relic-alert-push-notifications
- Cover image: https://pingroom.io/blog/new-relic-alert-push-notifications-cover.webp
- Cover description: Two PingRoom avatars pass one sealed signal through a miniature brass relay while Pingo watches from the workbench.

To send one selected New Relic issue to a shared phone Room, create a filtered New Relic workflow, connect it to a Bearer-authenticated webhook destination, verify and narrow the payload at a small relay, then forward fixed **activated** or **closed** copy to PingRoom.

This is a webhook recipe written by PingRoom, not a native New Relic integration. New Relic remains the source of truth for issue state, investigation, acknowledgement, notification history, and incident response. PingRoom carries one sparse shared signal to the people in the Room.

## Choose the notification route first

New Relic already supports mobile push. Its mobile app can open the issue, show details, and let the signed-in user acknowledge it. Use that route when a responder needs the New Relic workflow on their own device.

| Need                                                      | Better route                              | Why                                                                        |
| --------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------- |
| New Relic detail and acknowledgement for one user         | New Relic mobile push                     | The New Relic app owns the issue, evidence, and acknowledgement action     |
| One selected state change for a small shared group        | New Relic webhook → relay → PingRoom      | The Room receives fixed copy without exposing issue detail on lock screens |
| On-call schedules, escalation, acknowledgement, or paging | Your established incident-response system | PingRoom is not an on-call or escalation system                            |
| Rich team discussion around the issue                     | Your existing collaboration destination   | The collaboration tool owns threads, files, and investigation context      |

New Relic's [mobile alert guide](https://docs.newrelic.com/docs/mobile-apps/alerting-new-relic-mobile-apps/) documents the individual route. This guide covers the second case only.

For an illustrative setup, imagine a team that wants a shared signal only for critical issues affecting **checkout-api**. [Pingo](/Pingo), PingRoom's fictional CMO, appears at the miniature relay in the artwork. He cannot access New Relic, enter the private Room, choose the workflow, or send a Ping. The human team configures and rehearses the route.

## Create the private PingRoom destination

Open [your PingRoom Rooms](/app/rooms), choose a private Room, then open **Settings → Connections → From another app**.

1. Select **Add Webhook**.
2. Name it **New Relic shared signal**.
3. Keep **Quick Ping** on **Custom message**.
4. Use **Test** once, then copy the webhook URL.

Incoming webhooks require PingRoom Pro. The complete URL is a secret, so store it only in the relay's protected server-side configuration. Keep it out of New Relic payloads, source control, client code, screenshots, tickets, and logs. Regenerate it if it leaks.

The [incoming-webhook reference](/documents/webhooks) documents the current request fields, cooldown, rate limit, idempotency behavior, and error responses. A successful request means PingRoom accepted the Ping. It does not guarantee what every phone displays under every network, Focus, mute, or notification setting.

## Put an authenticated relay between New Relic and PingRoom

New Relic webhook destinations can send JSON by `POST` and use Basic or Bearer authentication. The relay below expects a separate random Bearer token and accepts only:

- one named workflow;
- `CRITICAL` priority;
- exactly one entity named `checkout-api`;
- the `ACTIVATED` or `CLOSED` lifecycle state;
- a non-empty issue ID and trigger time.

It never forwards the issue title, entity, policy, metric, value, runbook, or New Relic URL. Store these Worker secrets and variables:

```text
NEW_RELIC_BEARER_TOKEN=<a separate random secret>
NEW_RELIC_WORKFLOW_NAME=PingRoom shared signal
NEW_RELIC_PRIORITY=CRITICAL
NEW_RELIC_ENTITY_NAME=checkout-api
PINGROOM_WEBHOOK_URL=<the complete secret PingRoom URL>
```

Use this dependency-free Cloudflare Worker module:

```js
const encoder = new TextEncoder();
const MAX_BODY_BYTES = 16_384;

function reply(status, error) {
  return Response.json({ error }, { status });
}

async function sha256(value) {
  const bytes = await crypto.subtle.digest("SHA-256", encoder.encode(value));
  return [...new Uint8Array(bytes)]
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");
}

function sameHex(left, right) {
  if (!/^[a-f0-9]{64}$/i.test(left) || !/^[a-f0-9]{64}$/i.test(right)) {
    return false;
  }
  let different = 0;
  for (let index = 0; index < 64; index += 1) {
    different |= left.charCodeAt(index) ^ right.charCodeAt(index);
  }
  return different === 0;
}

export default {
  async fetch(request, env) {
    if (request.method !== "POST") return reply(405, "method_not_allowed");

    const required = [
      "NEW_RELIC_BEARER_TOKEN",
      "NEW_RELIC_WORKFLOW_NAME",
      "NEW_RELIC_PRIORITY",
      "NEW_RELIC_ENTITY_NAME",
      "PINGROOM_WEBHOOK_URL",
    ];
    if (
      !required.every(
        (name) => typeof env[name] === "string" && env[name].length > 0,
      )
    ) {
      return reply(500, "relay_not_configured");
    }

    const authorization = request.headers.get("Authorization") ?? "";
    const token = authorization.startsWith("Bearer ")
      ? authorization.slice(7)
      : "";
    const [provided, expected] = await Promise.all([
      sha256(token),
      sha256(env.NEW_RELIC_BEARER_TOKEN ?? ""),
    ]);
    if (!sameHex(provided, expected)) {
      return reply(401, "invalid_authorization");
    }

    const rawBody = await request.text();
    if (encoder.encode(rawBody).byteLength > MAX_BODY_BYTES) {
      return reply(413, "payload_too_large");
    }

    let payload;
    try {
      payload = JSON.parse(rawBody);
    } catch {
      return reply(400, "invalid_json");
    }

    if (payload.workflow_name !== env.NEW_RELIC_WORKFLOW_NAME) {
      return reply(403, "unexpected_workflow");
    }
    if (payload.priority !== env.NEW_RELIC_PRIORITY) {
      return reply(403, "unexpected_priority");
    }
    if (
      !Array.isArray(payload.entity_names) ||
      payload.entity_names.length !== 1 ||
      payload.entity_names[0] !== env.NEW_RELIC_ENTITY_NAME
    ) {
      return reply(403, "unexpected_entity");
    }
    if (
      typeof payload.issue_id !== "string" ||
      !payload.issue_id ||
      !["ACTIVATED", "CLOSED"].includes(payload.state) ||
      String(payload.triggered_at ?? "").length === 0
    ) {
      return reply(422, "invalid_transition");
    }

    const idempotencyKey = await sha256(
      `new-relic:${payload.issue_id}:${payload.state}:${payload.triggered_at}`,
    );
    const body =
      payload.state === "ACTIVATED"
        ? {
            title: "New Relic issue activated",
            message: "Selected service issue needs attention.",
          }
        : {
            title: "New Relic issue closed",
            message: "Selected New Relic issue is closed.",
          };

    const response = await fetch(env.PINGROOM_WEBHOOK_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Idempotency-Key": idempotencyKey,
      },
      body: JSON.stringify(body),
    });

    return response.ok
      ? new Response(null, { status: 204 })
      : reply(502, "pingroom_delivery_failed");
  },
};
```

The production receipt keeps a slightly more defensive version of this module and its local verifier.

## Configure the New Relic destination and workflow

New Relic's [notification integration guide](https://docs.newrelic.com/docs/alerts/get-notified/notification-integrations/) documents webhook destinations, Bearer tokens, JSON templates, preview, and test notifications.

1. In **Alerts**, open **Destinations** and create a **Webhook** destination named **PingRoom relay**.
2. Set the endpoint to the public HTTPS URL of your relay—not the PingRoom webhook URL.
3. Turn on authorization, choose **Bearer Token**, and enter the same secret stored as `NEW_RELIC_BEARER_TOKEN`.
4. Open **Alerts → Enrich and Notify → Workflows** and add a workflow named **PingRoom shared signal**.
5. Filter it to the selected team, condition, policy, or entity. The relay still checks the exact workflow, priority, and entity after the filter.
6. Attach the webhook destination. Under **Notify when**, keep **Activated** and **Closed**. Remove acknowledgement, investigation, priority-change, and other-update notifications from this sparse route.
7. Replace the webhook message with this valid JSON template:

```json
{
  "issue_id": {{json issueId}},
  "state": {{json state}},
  "priority": {{json priority}},
  "workflow_name": {{json workflowName}},
  "entity_names": {{json entitiesData.names}},
  "triggered_at": {{json triggeredAt}}
}
```

New Relic's [workflow-variable reference](https://docs.newrelic.com/docs/alerts/get-notified/custom-variables-alert-event-workflows/) defines those values. Preview the rendered JSON before saving. Then send a test notification; New Relic notes that a workflow test needs existing issue data matching the filter.

## Rehearse the narrow route

Use a non-critical test condition and a test Room first.

1. Activate one matching critical issue for `checkout-api`.
2. Confirm the Room receives **New Relic issue activated — Selected service issue needs attention.**
3. Close the test condition and confirm **New Relic issue closed — Selected New Relic issue is closed.**
4. Replay the exact activated payload and confirm the relay reuses the same PingRoom idempotency key.
5. Send a wrong Bearer token, workflow, priority, entity, two-entity list, `CREATED` state, and malformed body. Each must send nothing to PingRoom.
6. Lock a test phone and confirm the fixed copy reveals no service name, issue title, metric, threshold, customer, or investigation link.
7. Check New Relic's **Issue notification log** for the destination status and payload. Keep that log as the delivery evidence from New Relic.

The local fixture for this article passed activated, closed, exact-retry, bad-token, wrong-workflow, wrong-priority, wrong-entity, multiple-entity, unexpected-state, missing-issue, malformed-JSON, and failed-forward cases with a mocked PingRoom endpoint. No live New Relic organization, PingRoom Room, or physical phone was used.

![Two PingRoom avatars rehearse one raised activated token and one settled closed token at a miniature relay bench while Pingo watches between them.](/blog/new-relic-alert-push-notifications-1.webp)

At the miniature bench, one human raises the activated marker and another settles the closed marker. Pingo watches the handoff with the same expression he brings to every unnecessary dashboard refresh. The humans still own the workflow, secrets, relay, and Room; his fictional Chief Marketing Officer title grants no system access or authority.

## Read a closed signal carefully

An activated Ping means New Relic sent an authenticated payload matching the selected workflow, priority, entity, and state, and PingRoom accepted the fixed signal. It does not prove the service is unavailable, a phone displayed the Ping, or anyone acknowledged the issue.

A closed Ping means New Relic reported the selected issue as `CLOSED`. New Relic documents that closure can follow closed alert events, TTL expiry, or prolonged inactivity. It does not prove every related system recovered. That is why the fixed copy says only that the issue is closed.

Keep issue titles, metrics, links, acknowledgement, and investigation in New Relic. Keep paging, escalation, and incident records in the response system your team trusts. PingRoom's idempotency protects immediate exact retries; it is not a permanent incident ledger.

For broader ownership and severity design, read [how to route monitoring alerts](/blog/monitoring-alerts-for-teams). For PingRoom's request and response contract, use the [webhook-to-push guide](/blog/webhook-to-push-notification).

When the route is deliberately this narrow, [connect the Room in PingRoom](/i) and rehearse both states before using it for real work.
