Guide to New Relic Webhooks: Features and Best Practices
New Relic webhooks carry your alerts out of the observability platform. When an alert condition opens an issue, or the issue is acknowledged or closed, a New Relic workflow can POST a JSON notification to your own service, so you can open tickets, page people through a tool New Relic does not integrate with, run automated remediation, or record incidents in your own systems.
This guide covers how Webhook destinations and workflows fit together, how to authenticate notifications with HTTP Basic credentials, how to shape the payload with Handlebars, and the practices that make a New Relic receiver reliable.
What are New Relic webhooks?
In New Relic Alerts, a workflow decides which issues to notify about and where. A destination is where notifications go. A Webhook destination is a URL that receives an HTTP POST with a JSON body whenever a workflow that uses it fires.
The body is not fixed. New Relic starts you from a default JSON template, and you can rewrite it with Handlebars variables such as issueId, issueTitle, issuePageUrl, priority and state. Whatever your template renders is what your endpoint receives, so there is no New Relic event type to route on unless your template includes one.
New Relic does not sign webhook requests. The destination can carry an Authorization header, with either Basic Authentication or a Bearer Token, and you can add custom headers whose values New Relic encrypts and masks.
New Relic webhook features
| Feature | Details |
|---|---|
| Configuration | Alerts > Destinations > Webhook, then a workflow that notifies it |
| Method and format | POST, JSON body |
| Payload | A default JSON template, editable with Handlebars variables. It must render to valid JSON to be saved |
| Authorization | Optional: Basic Authentication or Bearer Token |
| Custom headers | Encrypted and masked from users and internal logs. A destination header overrides the same key on the channel |
| Secure URL | Path and query secrets encrypted after the domain |
| Signature and timestamp | None |
| Event type | None. Defined by your template |
| Testing | Send test notification from the workflow's template editor |
| Two-way sync | Acknowledge or close issues through NerdGraph |
| Timeout, retries, source IPs | Not documented |
Payloads
Because the payload is a template, the useful question is what to put in it. New Relic's own templates for other tools show the variables available. Its xMatters template, for example, builds an incident_id from issueId, an incident_url from issuePageUrl, an incident_acknowledge_url from issueAckUrl, and derives a current_state of closed, acknowledged or open from whether issueClosedAt or issueAcknowledgedAt is set.
A small template for your own receiver might be:
{
"issue_id": {{json issueId}},
"title": {{json issueTitle}},
"priority": {{json priority}},
"state": {{json state}},
"url": {{json issuePageUrl}},
"closed_at": {{#if issueClosedAtUtc}} {{json issueClosedAtUtc}} {{else}} null {{/if}}
}
Use {{json ...}} for strings so quotes in titles do not break the JSON, and wrap optional variables in {{#if}}: New Relic notes that "undefined type" errors usually mean an attribute does not exist on the issue. The Preview pane shows the rendered payload, and the editor will not save a template that does not produce valid JSON.
Inspect New Relic webhooks as they arrive. Point a Webhook destination at a Hookdeck Inspect URL and send a test notification to see exactly what your template renders, with no account or setup required.
Setting up New Relic webhooks
Choose a username and a long random password first, for example with openssl rand -hex 32 for the password.
- Go to one.newrelic.com > All capabilities > Alerts, click Destinations, and select Webhook.
- Enter a Webhook name and the Endpoint URL.
- Turn on Use authorization, choose Basic Authentication, and enter the username and password.
- Save the destination.
- Open Alerts > Workflows, edit a workflow or add one, and choose your Webhook destination.
- Edit the payload template, check the Preview, and click Send test notification.
To route through Hookdeck, create a Hookdeck source with the New Relic type and use its URL as the endpoint URL. The source asks for a Username and Password: enter the same pair. It accepts POST.
The Hookdeck source checks HTTP Basic credentials only. If you choose Bearer Token, or authenticate with a custom header, the New Relic source type will not verify the request. Hookdeck also never answers with a 401 challenge, so the credentials have to be sent with the first request. New Relic's docs do not describe the exact header it sends, so confirm on your first test notification that it arrives with an Authorization: Basic header.
Securing New Relic webhooks
With Basic Authentication, every notification carries Authorization: Basic <base64(username:password)>. Decode it, split on the first colon, and compare the username and password with your stored values in constant time.
const crypto = require('crypto');
const express = require('express');
const USERNAME = process.env.NEW_RELIC_WEBHOOK_USERNAME;
const PASSWORD = process.env.NEW_RELIC_WEBHOOK_PASSWORD;
function safeEqual(a, b) {
// timingSafeEqual throws on unequal lengths, so check first.
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
function verifyBasicAuth(header) {
if (!USERNAME || !PASSWORD || typeof header !== 'string') return false;
const match = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(header);
if (!match) return false;
const decoded = Buffer.from(match[1], 'base64');
const colon = decoded.indexOf(0x3a); // split on the first colon
if (colon === -1) return false;
const userOk = safeEqual(decoded.subarray(0, colon), Buffer.from(USERNAME, 'utf8'));
const passOk = safeEqual(decoded.subarray(colon + 1), Buffer.from(PASSWORD, 'utf8'));
return userOk && passOk;
}
const app = express();
app.post('/webhooks/new-relic', express.raw({ type: '*/*' }), (req, res) => {
if (!verifyBasicAuth(req.get('authorization'))) {
return res.sendStatus(401);
}
let notification;
try {
notification = JSON.parse(req.body.toString('utf8'));
} catch {
return res.sendStatus(400);
}
// Fields are whatever your template renders, e.g. notification.issue_id and notification.state.
res.sendStatus(200);
});
The same check in Python:
import base64
import binascii
import hmac
import os
USERNAME = os.environ.get("NEW_RELIC_WEBHOOK_USERNAME", "")
PASSWORD = os.environ.get("NEW_RELIC_WEBHOOK_PASSWORD", "")
def verify_basic_auth(header) -> bool:
if not USERNAME or not PASSWORD or not header:
return False
scheme, _, encoded = header.partition(" ")
if scheme.lower() != "basic":
return False
try:
decoded = base64.b64decode(encoded.strip(), validate=True)
except (binascii.Error, ValueError):
return False
user, sep, password = decoded.partition(b":")
if not sep:
return False
user_ok = hmac.compare_digest(user, USERNAME.encode("utf-8"))
pass_ok = hmac.compare_digest(password, PASSWORD.encode("utf-8"))
return user_ok and pass_ok
Basic credentials are static. They authenticate the sender, not the body, so a modified payload still passes, and with no timestamp a captured request can be replayed. Serve the endpoint over HTTPS only, use a long random password, and change it on the destination and in your environment together if it might have leaked.
Make New Relic webhooks production-ready. Hookdeck Event Gateway checks the Basic credentials you configure, queues every alert notification durably, and retries delivery to your service on a schedule you control.
New Relic webhook limitations and pain points
Only one of three auth options fits the source type
The Problem: A destination set up with a Bearer Token or an encrypted custom header never verifies in Hookdeck's New Relic source.
Why It Happens: New Relic offers Basic Authentication, Bearer Token and custom headers. Hookdeck's New Relic source type checks HTTP Basic credentials only.
Workarounds:
- Use Basic Authentication on the destination.
- If you are tied to a bearer token or custom header, check it in your own receiver instead.
How Hookdeck Can Help: With Basic Authentication, the New Relic source compares the username and password you enter. Hookdeck answers New Relic with a 200 either way, but requests without matching credentials are recorded as failed verification and never reach your service.
No documented delivery guarantees
The Problem: You cannot tell from the docs how long New Relic waits for your endpoint, whether it retries, or what happens to a notification when your service is down.
Why It Happens: The Webhook destination documentation covers configuration and payloads, not delivery behaviour.
Workarounds:
- Respond quickly and process afterwards, so a slow handler never becomes a lost alert.
- Reconcile open issues against New Relic through NerdGraph, so a missed notification is noticed.
How Hookdeck Can Help: Hookdeck accepts each notification and stores it, then delivers to your service with retries you configure. You can replay any notification after a fix, and issues alert you when deliveries to your service fail.
The template is the contract
The Problem: Someone edits a workflow's template and your receiver starts failing, or a variable that does not exist on some issues renders as an error.
Why It Happens: The payload is whatever the template renders, per workflow. Different workflows can send different shapes to the same endpoint.
Workarounds:
- Keep one template for every workflow that targets the same endpoint, and treat changes to it like an API change.
- Guard optional variables with
{{#if}}and give them defaults. - Include a constant such as
"source": "new-relic"and a schema version in the template.
How Hookdeck Can Help: Hookdeck keeps every request with its full body, so you can see exactly what a changed template sent and replay it against your fixed handler. Transformations can normalise differing shapes before they reach your service.
Several notifications per issue
The Problem: One issue can produce several notifications as it opens, is acknowledged and closes, and your receiver has to reconcile them.
Why It Happens: A workflow can notify on more than one kind of issue update, and nothing in the delivery itself orders them unless your template includes timestamps.
Workarounds:
- Include
issueIdand the relevant timestamps in your template. - Upsert by issue ID and only move state forward.
How Hookdeck Can Help: Hookdeck deduplication can drop repeated notifications based on fields you choose, such as the issue ID and state.
Best practices
Design the template for your receiver
Include an issue identifier, the state, priority, a link back to New Relic and the timestamps you care about. Use {{json}} for every string so the output stays valid JSON.
Make handlers idempotent
Key on the issue ID plus its state or the relevant timestamp, and store that key before you act. See our guide to webhook idempotency.
Close the loop with NerdGraph
If your receiver handles the incident, acknowledge or close the issue back in New Relic through NerdGraph, so both systems agree on its state.
Acknowledge fast and process asynchronously
Remediation or ticket creation can take a while. Verify the credentials, store the notification, return 200, and do the work afterwards. See why to process webhooks asynchronously.
Conclusion
New Relic sends alert notifications to Webhook destinations as an HTTP POST whose JSON body is your own Handlebars template, with no signature and no fixed event type. Use Basic Authentication on the destination, compare the decoded username and password in constant time over HTTPS, put an issue ID and state in your template, and build the handler to cope with duplicates and undocumented delivery behaviour.
Hookdeck Event Gateway checks the Basic credentials, keeps every notification, and retries and replays delivery to your service, so an outage on your side does not mean a missed alert.
Get started with Hookdeck for free and handle New Relic webhooks reliably in minutes.