Diffinery
Accounts: Notifications
Docs / Accounts

Notifications

In-app notifications and email from Diffinery: every email group and template, settings, watching, thread subscriptions, unsubscribe links, headers and the API.

Diffinery tells you about activity in two places: the notifications list in the web UI, and email. Both follow GitHub's rules: you hear about issues and pull requests you take part in, everything in repositories you watch, and workflow runs you started. This page explains what you get, how to change it, and every email Diffinery can send.

The notifications list and notification settings

Two pages share the name, and they do different things:

PageWhereWhat it is for
Notifications (the list)The bell in the header, or /notificationsReading what happened: your recent notifications, marking them read
Notification settingsSettings → Notifications (/settings/notifications), or the gear button on the listChoosing what you hear about, in the list and by email; watched repositories; your recent emails

The list only shows what your settings let through. To get fewer (or more) entries in the list, change the On Diffinery column in the settings; to change your email, change the Email column.

The notifications list

The bell in the header opens Notifications (/notifications). It has two views, Unread and All, and shows your 100 most recent notifications. Each entry has an icon for its kind (a pull request, an issue, a comment, a failed run in red, an organization, a repository or an invitation), a title such as diffy commented on acme/website#42: Cache build artifacts, its kind (for example issue comment, pull request review or run failed) and when it happened.

  • Click an entry to open what it is about; that marks it read.
  • Click the check mark (Mark as read) next to an unread entry to mark only that one read.
  • Click Mark all as read to clear the list.
  • Click the gear button (Notification settings) to open Settings → Notifications.

Your dashboard also shows up to 8 unread notifications under Unread notifications.

You get an in-app notification for:

  • issue and pull request activity you take part in, when Participating → On Diffinery is on,
  • activity in repositories you watch with All activity, when Watching → On Diffinery is on,
  • failed workflow runs you started, when Actions → On Diffinery is on,
  • a run waiting for your approval to deploy to an environment where you are a required reviewer ("Deployment to production in acme/website is waiting for your review"), when Actions → On Diffinery is on,
  • someone inviting you by username to an organization or a repository (kind invitation, for example "<admin> invited you to acme as member"); it opens Settings → Invitations (see Invitations you receive),
  • someone giving you a repository role at once, without an invitation, because you are a member of the organization that owns the repository or already a collaborator on it (kind repo access, for example "<admin> gave you write access to acme/website"). This comes from Add people, the role menu on Settings → Collaborators or the API.

The last two are always sent, whatever your settings. The invitation email belongs to the Account group, which can't be turned off; the access email belongs to the Repositories group.

Your own actions never create a notification for you. Other repository and organization events (organization role changes, removals, repositories created or deleted), and security and account events, are sent by email only.

Email groups

Every email belongs to one group. Security and account emails always send; you can turn the others off.

GroupEmailsCan be turned offDefault
SecurityNew sign-in from a browser or device not seen before (and every email-recovery sign-in), passkey added or removed, access token created or about to expire, agent added, model API key added, push blocked or push protection bypassed, account disabled or enabled, and for site administrators a new security reportNoOn
AccountInvitations, welcome, sign-in links, sign-up codes, test email, agent review's daily limit reachedNoOn
ParticipatingIssues and pull requests you opened, commented on, reviewed, were assigned, were asked to review, were @mentioned in or subscribed to: new issues and pull requests, comments, reviews, pushes, merges, closes, reopens, assignments and review requestsYesOn
WatchingEverything else in repositories you watch with All activityYesOn
ActionsWorkflow runs you started (failed runs only, unless you turn off Only failed runs), and scheduled runs in repositories you watchYesOn, failures only
RepositoriesRepositories created or deleted in your organizations (for owners and admins), your own new repositories, and repository access granted, changed or removedYesOn
OrganizationsYour organization role added, changed or removed (with who did it), invitations you sent being accepted, and access requests (for site administrators)YesOn
Morning digestToday by email, once a day at the hour you chooseYesOff

Notification settings

Open Settings → Notifications (/settings/notifications). The top of the page shows the address emails go to (your account's email address) and the address they come from (notifications@diffinery.com).

The Notify me about table has a row per group with an On Diffinery checkbox (the notifications list) and an Email checkbox:

RowOn DiffineryEmailExtra option
ParticipatingYesYes
WatchingYesYes
ActionsYesYesOnly failed runs (on by default)
RepositoriesNoYes
OrganizationsNoYes
Security and accountNoAlways on (locked)

Below the table:

  • Email me about my own comments and changes (off by default). When on, you also get emails about comments, reviews and changes you made yourself, like GitHub's "Include your own updates".
  • Watch repositories I create (All activity) (on by default). New repositories you create, in the web UI or through the API, are watched with All activity.

Under Morning digest:

  • Email me a morning digest (off by default).
  • Hour and Time zone: when it goes out, in your time zone. Until you save one, the time zone is your browser's.
  • On Saturdays and Sundays too (off by default).

When the digest is on, the page says when the next one goes out. See The morning digest.

Click Save notification settings. You see "Notification settings saved."

The same page lists Watched repositories (every repository you watch or ignore, with a menu to change the level) and Recent emails to you (the last 20, with their status), and has Send me a test email and Send me my digest now buttons.

Who gets notified about issues and pull requests

For each event on an issue or pull request, Diffinery works out who is taking part:

You are notified becauseReason (X-Diffinery-Reason)
Your review was requested on the pull requestreview_requested
You are assignedassign
You were @mentioned in the text of this event (the description, comment or review)mention
You opened the issue or pull requestauthor
You commented on it or reviewed it beforecomment
You clicked Subscribe on itmanual
You watch the repository with All activitysubscribed

When several apply, the email gives the first one in this order. Mentions use @username outside code blocks and inline code.

What sends:

EventWho hears about it
Issue or pull request openedParticipants (assignees, requested reviewers, people mentioned) and watchers
CommentParticipants and watchers
Review submittedParticipants and watchers
Closed, merged or reopenedParticipants and watchers
New commits pushed to a pull requestParticipants only
Someone assignedThe new assignees and other participants, not watchers
Review requestedThe requested reviewers and other participants, not watchers
Title or description edited, merge queue changesNobody

Rules that apply to every event:

  • Your own actions don't notify you, unless you turn on Email me about my own comments and changes (email only; such emails carry the reason your_activity).
  • A repository set to Ignore sends you nothing about its issues, pull requests and workflow runs.
  • A muted thread (you clicked Unsubscribe) sends you nothing, except when that event @mentions you, assigns you or asks for your review.
  • You must still be able to read the repository. People who lost access stop hearing about it.
  • Agents don't receive email.

Watch a repository

The Watch menu at the top of every repository sets how much you hear about it:

Menu itemLevelEffect
Watch: participatingParticipating and @mentionsThe default: only threads you take part in
Watch: all activityAll activityEvery new issue, pull request, comment, review and state change, plus scheduled workflow runs
Watch: ignoreIgnoreNothing about this repository's issues, pull requests and workflow runs, even runs you started

Choosing a level saves it right away ("Watching acme/website: All activity."). You can also change levels from the Watched repositories list in Settings → Notifications.

With the API (GitHub's repository subscription endpoints):

# Watch all activity
curl -X PUT https://diffinery.com/api/v3/repos/acme/website/subscription \
  -H "Authorization: Bearer dfy_..." -H "Content-Type: application/json" \
  -d '{"subscribed": true}'

# Ignore the repository
curl -X PUT https://diffinery.com/api/v3/repos/acme/website/subscription \
  -H "Authorization: Bearer dfy_..." -H "Content-Type: application/json" \
  -d '{"ignored": true}'

# Back to participating only
curl -X DELETE https://diffinery.com/api/v3/repos/acme/website/subscription \
  -H "Authorization: Bearer dfy_..."

Watching, ignoring and subscribing to issues also work on archived repositories, which otherwise refuse every change.

GET /api/v3/repos/{owner}/{repo}/subscription returns {"subscribed": true|false, "ignored": true|false, ...}, or 404 not subscribed when you are on the default participating level (as GitHub does). PUT with {"subscribed": false} also returns you to participating. Changing the level needs a write or admin token.

Subscribe to or mute an issue or pull request

The sidebar of every issue and pull request has a Notifications section with one button:

  • Subscribe follows the thread even if you aren't taking part: "Subscribed. You'll be notified about all activity."
  • Unsubscribe mutes it: "Unsubscribed. You'll still be notified if you're @mentioned, assigned or asked to review."

The text under the button says why you are or aren't receiving notifications, for example "You're receiving notifications because you commented." or "You muted this pull request."

Workflow run notifications

When a workflow run finishes:

Run started byWho is notified
A person (a push, a pull request, a manual dispatch)That person
An agentPeople watching the repository with All activity (the agent's owner isn't notified directly yet)
Diffinery itself (for example a schedule)People watching the repository with All activity

Failed and timed-out runs send an email and an in-app notification. Successful runs send an email only to people who turned off Only failed runs. Cancelled runs send nothing. The email lists every job with its result and the first failure message, and links to the run. Set a repository to Ignore to hear nothing about its runs, for example a test repository whose CI you expect to fail.

Every email in a group you can turn off has unsubscribe links in its footer, and List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers (RFC 8058), so mail apps show their own Unsubscribe button.

Footer linkWhereWhat it does
Mute this threadIssue and pull request emailsMutes that issue or pull request, like Unsubscribe on the page
Stop watching acme/websiteEmails you got because you watch the repositorySets the repository back to participating
Unsubscribe from emails like thisEvery email you can turn offTurns off email for that group (for example Watching)

The mail app's one-click button (List-Unsubscribe) turns off email for the group the email belongs to, the same as Unsubscribe from emails like this: for an issue or pull request email, that's every Participating email (or every Watching one, when you got it because you watch the repository). To mute just one thread, use Mute this thread in the footer instead. You can turn the group back on in notification settings.

The links are signed, so they work without signing in and can't be altered to change someone else's settings. Each link works for a year after the email was sent (links from before links carried an expiry work until October 16, 2027); after that, change what you get in notification settings. Opening one shows a page naming the change (for example "Mute acme/website#42") and the account's username, though not its email address, with a button to confirm; after confirming you can click Undo. Security and account emails have no unsubscribe links.

Email headers

Every email has an HTML and a plain-text version and these headers, which you can use in mail filters:

HeaderValue
Fromnotifications@diffinery.com. The display name is the person who acted, for issue and pull request emails (diffy (Diffinery)), otherwise Diffinery.
SubjectIssue and pull request emails: [acme/website] <title> (PR #42) or (Issue #37), with Re: for every email after the first. Others start with [acme/website] or [Diffinery].
X-Diffinery-ReasonWhy you got the email (see below), like GitHub's X-GitHub-Reason
X-Diffinery-KindThe email template, for example thread, run or signin_new (see Every email Diffinery sends)
X-Diffinery-RecipientYour username
X-Diffinery-Repositoryowner/repo (or the organization) the email is about, when there is one
List-IdFor repository emails, acme/website <website.acme.diffinery.com>
References, In-Reply-ToAll emails about one issue or pull request share References: <acme/website/pull/42@diffinery.com>; every email after the first also has it as In-Reply-To, so mail apps group them into one conversation
List-Unsubscribe, List-Unsubscribe-PostOn emails you can turn off
Precedence: listOn emails you can turn off
Auto-Submitted: auto-generatedOn every email

X-Diffinery-Reason values

ValueMeaning (as written in the email footer)
authorYou opened this thread.
commentYou commented (or reviewed).
mentionYou were mentioned.
assignYou were assigned.
review_requestedYour review was requested.
manualYou subscribed to this thread.
subscribedYou are watching this repository.
your_activitySomething you did on Diffinery (your own updates, a repository you created).
ci_activityA workflow run triggered by you, or in a repository you watch.
security_alertA security notice about your account. These can't be turned off.
invitationSomeone invited this email address or your account to Diffinery, an organization or a repository.
adminYou are an administrator (of the organization, repository or instance).
accountYou have a Diffinery account (account and membership changes).
signupSomeone asked to create an account with this address through open sign-up (the sign-up code).
digestYou turned on the morning digest in your notification settings.

When Diffinery stops emailing you

When email to your address bounces for good (the mailbox doesn't exist or the server refuses it), or you mark an email from Diffinery as spam, Diffinery puts your address on its suppression list and sends nothing to it any more: no notifications, and no security alerts, sign-in links or account recovery emails either. A site administrator can also suppress an address by hand.

Settings → Email (/settings/email) shows whether your address is suppressed, since when and why, and the notifications settings page shows a warning too. To get email again after a bounce or a spam report:

  1. Make sure the inbox works (and, after a spam report, that you want Diffinery's email).
  2. On Settings → Email, click Send a verification email. It is the one email that goes to a suppressed address, and you can ask for 3 an hour.
  3. Open the link in it within 24 hours, signed in to the same account, and click Confirm and get email again.

If a site administrator suppressed your address, only an administrator can lift it. If the verification email itself fails with E_RECIPIENT_SUPPRESSED, Cloudflare's own list still holds the address: ask a site administrator.

With the API: GET /api/v3/diffinery/email returns your address and suppressed (null, or reason, detail, created_at and owner_can_lift), and POST /api/v3/diffinery/email/verification sends the verification email.

Every email Diffinery sends

The Kind column is the X-Diffinery-Kind header. Site administrators can preview every one of these under Settings → Email (see Site administration).

KindSubject (example)GroupReasonSent when
thread[acme/website] Cache build artifacts (PR #42)Participating or Watchingauthor, comment, mention, assign, review_requested, manual, subscribed or your_activityActivity on an issue or pull request (see the next table)
run[acme/website] Run failed: CI - main (3f9c2a1)Actionsci_activityA workflow run you started failed or timed out (or succeeded, if you asked for all runs)
deployment_review_requested[acme/website] Deployment to production is waiting for your reviewActionsreview_requestedA run waits for a required reviewer of an environment, and you are one of them (not when you started the run)
signin_new[Diffinery] New sign-in to your accountSecuritysecurity_alertA passkey sign-in from a browser and passkey combination not seen before, or any email-recovery sign-in
passkey_added[Diffinery] A passkey was added to your accountSecuritysecurity_alertYou added a passkey in settings or with a sign-in link
passkey_removed[Diffinery] A passkey was removed from your accountSecuritysecurity_alertYou removed a passkey
token_created[Diffinery] A personal access token was added to your account (or A token was created for the agent review-bot)Securitysecurity_alertA token was created for you or your agent, from the web UI, CLI or API
token_expiring[Diffinery] Your token "ci-deploy" expires on <date>Securitysecurity_alertAbout 7 days before a token expires (once per token, for tokens that last more than 8 days)
agent_created[Diffinery] A new agent was added: review-botSecuritysecurity_alertYou created an agent
model_key_added[Diffinery] Your Anthropic API key was added to Diffinery (or OpenAI, OpenRouter)Securitysecurity_alertYou saved a model API key for agent tasks
push_blocked[acme/website] Your push was blocked: possible secretsSecuritysecurity_alertPush protection rejected your git push, or a commit made in the web editor, through the REST API or over MCP (subject Your commit was blocked). For an agent, its owner is told.
push_bypassed[acme/website] Push protection was bypassedSecuritysecurity_alertA repository admin pushed past push protection, or committed a flagged file through the commits API with allow_secrets; sent to that admin and the repository's admins
account_status[Diffinery] Your account was disabled or Your account was enabledSecurityaccountA site administrator disabled your account, or enabled it again
security_report[Diffinery] New security reportSecurityadminSomeone sent a private report through /security/report (sent to every active site administrator). It holds only the report's summary and a link to it in Site administration.
early_access_confirm[Diffinery] Confirm your early access requestAccountearly_accessSomeone asked for early access with this address: the link that confirms the request. Sent to the address typed, not to an account.
early_access_known[Diffinery] We already have your early access request, You're already invited or You already have a Diffinery accountAccountearly_accessSomeone asked for early access again with an address whose request is already confirmed, declined or invited, or that belongs to an active account
early_access_remove[Diffinery] Remove your early access requestAccountearly_accessSomeone asked to remove the early access request for this address: the link that deletes it
invite@diffy invited you to join the acme organization on DiffineryAccountinvitationSomeone invited your email address (organization, repository or instance), or your username (organization or repository; the button is View invitation and opens Settings → Invitations)
welcomeWelcome to Diffinery, @diffyAccountaccountYou created your account from an invite or through open sign-up
signup_code[Diffinery] Your sign-up codeAccountsignupWith open sign-up, someone asked for a code for an address without an account. The code is in the message, not the subject.
signup_attempt[Diffinery] Someone tried to sign up with your email addressAccountaccountWith open sign-up, someone asked for a code for your address, which already has an account (no code is sent)
email_verify[Diffinery] Confirm your email address to get email againAccountaccountYou asked for it on Settings → Email while your address was suppressed. It is the only email sent to a suppressed address. See When Diffinery stops emailing you.
signin_link[Diffinery] Your one-time sign-in linkAccountaccountA site administrator created a sign-in link for you
review_limit_reached[acme/website] Agent review reached its daily limitAccountyour_activityAgent review on a repository whose reviews use your model key reached its daily limit (at most once a day per repository)
test[Diffinery] Test emailAccountaccountYou clicked Send me a test email (or used the API)
digest[Diffinery] Today: 2 need you, 3 mergedMorning digestdigestAt the hour you chose, when something needs you or happened since the last one; or when you click Send me my digest now
invite_accepted[Diffinery] @diffy accepted your invitationOrganizationsaccountSomeone accepted an invite you created
access_request[Diffinery] newcomer@example.com asked for accessOrganizationsadminA person waiting for an invite requested access (sent to site administrators)
org_membership[Diffinery] You're now a member of acmeOrganizationsaccountYour organization role was added, changed or removed by an owner or admin. The email names who added you ("Added by") or who changed your role ("Changed by").
repo_access[acme/website] You now have write access to acme/websiteRepositoriesaccountYour collaborator role on a repository was added, changed or removed
repo_created[acme/website] New private repositoryRepositoriesyour_activity or adminYou created a repository in the web UI (not when a token or script creates it), or someone created one in an organization where you are an owner or admin
repo_deleted[acme/website] Repository deletedRepositoriesadminSomeone else deleted a repository you own or that belongs to an organization where you are an owner or admin
repo_transferred[acme-labs/website] Repository transferred from acme/websiteRepositoriesadminSomeone else transferred a repository away from or to you, or an organization where you are an owner or admin

Issue and pull request emails (thread) come in these variants:

EventTitle in the email
Opened@diffy wants to merge cache-artifacts into main (pull request) or @diffy opened acme/website#37 (issue); includes the description, the pull request's intent and recent commits
Comment@diffy commented on acme/website#42, with the comment
Review@diffy approved, requested changes on or reviewed acme/website#42, with the review and its line comments
Closed@diffy closed acme/website#37 as completed (or as not planned)
Merged@diffy merged acme/website#42 into main
Reopened@diffy reopened acme/website#37
Assigned@diffy assigned you to acme/website#37
Review requested@diffy requested your review on acme/website#42
Pushed@diffy pushed 2 commits to cache-artifacts, with the commits

Send a test email

Click Send me a test email on Settings → Notifications. Diffinery sends it right away (not through the queue) and shows "Test email sent to <address>." or the reason it wasn't sent, for example "The test email was skipped: ...".

You can send at most 5 test emails an hour; more answer 429 you can send at most 5 test emails an hour; try again later.

With the API (needs a write or admin token that isn't limited to repositories):

curl -X POST https://diffinery.com/api/v3/diffinery/emails/test -H "Authorization: Bearer dfy_..."
{ "status": "sent", "messageId": "..." }

status is sent, skipped or failed, with a detail when it wasn't sent.

Notifications API

Method and pathDescriptionToken scope
GET /api/v3/notificationsUnread notifications (add ?all=true for read ones too): id, kind, title, url, createdAt, readAtany
PUT /api/v3/notificationsMark all as read; returns 205write or admin, all repositories
GET /api/v3/diffinery/notification-settingsYour settings (see below)any
PUT /api/v3/diffinery/notification-settingsChange settings; send only the keys to changewrite or admin, all repositories
GET /api/v3/repos/{owner}/{repo}/subscriptionYour watch levelany
PUT /api/v3/repos/{owner}/{repo}/subscriptionWatch ({"subscribed": true}) or ignore ({"ignored": true})write or admin
DELETE /api/v3/repos/{owner}/{repo}/subscriptionBack to participatingwrite or admin
GET /api/v3/diffinery/emailsYour recent emails: kind, subject, status (sent, failed or skipped), detail, message_id, created_at. Query: kind, since (ISO time), per_page (default 50, up to 500)any
POST /api/v3/diffinery/emails/testSend yourself a test email nowwrite or admin, all repositories
POST /api/v3/diffinery/emails/digestSend yourself the morning digest now, even when it is off or has nothing in it (3 an hour)write or admin, all repositories
GET /api/v3/diffinery/emailYour email address and whether it is suppressedany
POST /api/v3/diffinery/email/verificationSend the email that lifts a bounce or complaint on your addresswrite or admin, all repositories

The settings object, with its defaults:

{
  "participating": { "web": true, "email": true },
  "watching": { "web": true, "email": true },
  "actions": { "web": true, "email": true, "failuresOnly": true },
  "repos": { "email": true },
  "orgs": { "email": true },
  "ownActivity": false,
  "autoWatch": true,
  "digest": { "email": false, "hour": 8, "timeZone": "UTC", "weekends": false }
}

digest.hour is 0 to 23 and digest.timeZone an IANA time zone, such as Europe/Istanbul; anything else returns 422. To get the digest at 7:00 in Istanbul:

curl -X PUT https://diffinery.com/api/v3/diffinery/notification-settings \
  -H "Authorization: Bearer dfy_..." -H "Content-Type: application/json" \
  -d '{"digest": {"email": true, "hour": 7, "timeZone": "Europe/Istanbul"}}'

For example, to stop watching emails and get every workflow run result:

curl -X PUT https://diffinery.com/api/v3/diffinery/notification-settings \
  -H "Authorization: Bearer dfy_..." -H "Content-Type: application/json" \
  -d '{"watching": {"email": false}, "actions": {"failuresOnly": false}}'

The response is the full settings object. An unknown key returns 422 unknown setting <key>. Only people have notification settings; agent tokens get 403 only people have notification settings.

Delivery

Emails are queued and sent through Cloudflare Email Sending from notifications@diffinery.com. A failed send is retried with increasing delays. Every email Diffinery tries to send is logged for 90 days with its status, which you can see under Recent emails to you or with GET /api/v3/diffinery/emails. A skipped email has a reason:

DetailMeaning
turned off <group> emailsYou turned off that group (for example turned off watching emails).
no email addressYour account has no email address.
account disabledDisabled accounts only get the email saying they were disabled or enabled.
email sending is not configured (no EMAIL binding)The instance can't send email; ask a site administrator.
address is suppressed: ...Email to your address bounced or was reported as spam, or a site administrator suppressed it. See When Diffinery stops emailing you.

How notifications differ from GitHub

  • The participating, watching and ignore rules, @mention handling, thread subscriptions, X-Diffinery-Reason (for X-GitHub-Reason) and the /repos/{owner}/{repo}/subscription API follow GitHub.
  • Diffinery has no custom watch level (such as releases or discussions only).
  • Settings are per group, for the notifications list and email separately. There are no per-organization email routes; every email goes to your account's address.
  • Security and account emails can't be turned off.
  • The notifications list shows your 100 most recent notifications and has no per-thread done or saved states.
  • Being added to an organization or a repository with Add people always creates an in-app notification, with no setting to turn it off.