Skip to main content
Sentry can send HTTP POST requests to any URL you control whenever something happens—a new issue is created, an error fires an alert, an issue is resolved, and more. There are two ways to set this up: Service Hooks for simple project-level notifications, and Sentry App webhooks for richer, event-driven integrations built on the Integration Platform.

Service Hooks

Service Hooks are the simplest way to receive Sentry notifications over HTTP. You configure a URL and a set of events, and Sentry sends a signed POST request to that URL whenever those events occur in a project.

Available events

EventWhen it fires
event.alertAn alert rule fires for an event
event.createdA new event is received and processed

Create a Service Hook

1

Enable Service Hooks for the project

Service Hooks require the servicehooks feature to be enabled for your project. Contact your Sentry administrator if you do not see the option below.
2

Open project settings

Go to Settings > [Project] > Service Hooks.
3

Add a hook

Click Add a new hook, enter your endpoint URL, and select the events you want to receive.
4

Save

Click Save. Sentry immediately starts sending events to your URL.

Create a Service Hook via API

You can also create Service Hooks programmatically using the Sentry API.
curl https://sentry.io/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/hooks/ \
  -H "Authorization: Bearer <your_auth_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/sentry-hook",
    "events": ["event.alert", "event.created"]
  }'
A successful response returns the hook details including the secret you use to verify incoming requests:
{
  "id": "4f9d73e63b7144ecb8944c41620a090b",
  "dateCreated": "2018-11-06T21:20:08.143Z",
  "url": "https://example.com/sentry-hook",
  "events": ["event.alert", "event.created"],
  "secret": "8fcac28aaa4c4f5fa572b61d40a8e084364db25fd37449c299e5a41c0504cbc2",
  "status": "active"
}
Store the secret securely. You need it to verify that incoming webhook requests actually come from Sentry. It is not shown again after creation.

Webhook payload

Sentry sends a JSON payload via HTTP POST to your endpoint. The exact structure depends on the event type, but every payload includes the event data in the request body.

Example event.alert payload

{
  "id": "abc123",
  "project": "my-project",
  "project_name": "My Project",
  "culprit": "raven.scripts.runner in main",
  "url": "https://sentry.io/organizations/my-org/issues/123/",
  "message": "This is an example Python exception",
  "triggering_rules": ["My Alert Rule"],
  "event": {
    "event_id": "9fac2ceed9344f2bbfdd1fdacb0ed9b1",
    "level": "error",
    "tags": [
      ["environment", "production"],
      ["release", "v1.2.3"]
    ],
    "platform": "python",
    "datetime": "2024-01-15T12:00:00.000000Z"
  }
}

Verify webhook signatures

Sentry signs every webhook request using HMAC-SHA256 with the hook’s secret. You should verify this signature before processing the payload to confirm the request came from Sentry. The signature is in the X-Sentry-Hook-Signature request header.
import hashlib
import hmac
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret_here"

@app.route("/sentry-hook", methods=["POST"])
def sentry_hook():
    signature = request.headers.get("X-Sentry-Hook-Signature", "")
    body = request.get_data()

    expected = hmac.new(
        key=WEBHOOK_SECRET.encode("utf-8"),
        msg=body,
        digestmod=hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(expected, signature):
        abort(401)

    payload = request.get_json()
    # process payload...
    return "", 200
Always use a constant-time comparison function (such as hmac.compare_digest in Python or crypto.timingSafeEqual in Node.js) when comparing signatures. Regular string comparison is vulnerable to timing attacks.

Sentry App webhooks

If you need richer webhook events—beyond event.alert and event.created—build a Sentry App using the Integration Platform. Sentry App webhooks support a much broader set of events:
ResourceEvents
issueissue.created, issue.resolved, issue.ignored, issue.assigned, issue.unresolved
errorerror.created
commentcomment.created, comment.updated, comment.deleted
installationinstallation.created, installation.deleted
metric_alertmetric_alert.critical, metric_alert.warning, metric_alert.resolved, metric_alert.open
event_alertevent_alert.triggered

Create a Sentry App

  1. Go to Settings > Developer Settings > New Internal Integration (for private use within your organization) or New Public Integration (to publish on the Sentry marketplace).
  2. Enter a name and webhook URL.
  3. Under Webhook, enable the resource categories you want to receive.
  4. Save the app and install it on your organization.
Sentry sends signed POST requests to your webhook URL for each subscribed event. The signature header is Sentry-Hook-Signature and uses the same HMAC-SHA256 scheme as Service Hooks.

Example issue.created payload

{
  "action": "created",
  "installation": {
    "uuid": "a8e5d37a-696c-4c54-aac1-4a51b40ce7d9"
  },
  "data": {
    "issue": {
      "id": "1234567890",
      "shortId": "MY-PROJECT-1A2B",
      "title": "TypeError: Cannot read properties of undefined",
      "culprit": "app/utils/api in fetchUser",
      "level": "error",
      "status": "unresolved",
      "firstSeen": "2024-01-15T12:00:00.000000Z",
      "lastSeen": "2024-01-15T12:00:00.000000Z",
      "count": 1,
      "project": {
        "id": "1",
        "name": "my-project",
        "slug": "my-project"
      }
    }
  },
  "actor": {
    "type": "application",
    "id": "sentry",
    "name": "Sentry"
  }
}

Respond to webhooks quickly

Sentry expects your endpoint to respond with a 2xx status code within a few seconds. If your endpoint takes longer to process the payload, acknowledge the request immediately and handle the work asynchronously.
from threading import Thread
from flask import Flask, request

app = Flask(__name__)

def process_payload(payload):
    # slow processing here
    pass

@app.route("/sentry-hook", methods=["POST"])
def sentry_hook():
    payload = request.get_json()
    Thread(target=process_payload, args=(payload,)).start()
    return "", 200  # respond immediately

Retry behavior

Sentry retries failed webhook deliveries if your endpoint returns a non-2xx response or times out. Make your endpoint idempotent so that processing the same event twice does not cause unintended side effects. You can use the event id field to deduplicate.