Complete notification management and push subscription handling.
type Notification struct {
ID ID
Type string
CreatedAt time.Time
Account Account
Status *Status
}Notification holds information for a Mastodon notification.
Fields:
ID - Unique notification identifierType - Notification type (see types below)CreatedAt - When notification was createdAccount - Account that triggered the notificationStatus - Associated status (nil for some types)Notification Types:
"mention" - Someone mentioned you in a status"reblog" - Someone reblogged your status"favourite" - Someone favourited your status"follow" - Someone followed you"follow_request" - Someone requested to follow you"poll" - A poll you voted in or created has ended"status" - Someone you enabled notifications for posted"update" - A status you interacted with was editedtype PushSubscription struct {
ID ID
Endpoint string
ServerKey string
Alerts *PushAlerts
}PushSubscription holds push notification subscription data.
Fields:
ID - Subscription identifierEndpoint - Push endpoint URLServerKey - Server's public key for encryptionAlerts - Alert type preferencestype PushAlerts struct {
Follow *Sbool
Favourite *Sbool
Reblog *Sbool
Mention *Sbool
}PushAlerts defines which notification types trigger push notifications.
Fields:
Follow - Enable push for followsFavourite - Enable push for favouritesReblog - Enable push for reblogsMention - Enable push for mentionsNote: Sbool is a special boolean type that handles JSON string booleans.
func (c *Client) GetNotifications(ctx context.Context, pg *Pagination) ([]*Notification, error)Returns notifications for the current user.
Parameters:
ctx - Context for cancellation/timeoutpg - Pagination parameters (optional)Returns: Slice of Notification objects or error
Example:
notifications, err := client.GetNotifications(ctx, nil)
if err != nil {
log.Fatal(err)
}
for _, notif := range notifications {
switch notif.Type {
case "mention":
fmt.Printf("@%s mentioned you: %s\n",
notif.Account.Acct, notif.Status.Content)
case "follow":
fmt.Printf("@%s followed you\n", notif.Account.Acct)
case "favourite":
fmt.Printf("@%s favourited your status\n", notif.Account.Acct)
case "reblog":
fmt.Printf("@%s reblogged your status\n", notif.Account.Acct)
}
}func (c *Client) GetNotificationsExclude(ctx context.Context, exclude *[]string, pg *Pagination) ([]*Notification, error)Returns notifications with specific types excluded.
Parameters:
ctx - Context for cancellation/timeoutexclude - Pointer to slice of notification types to excludepg - Pagination parameters (optional)Returns: Slice of filtered Notification objects or error
Example:
// Get all notifications except follows and follow requests
exclude := []string{"follow", "follow_request"}
notifications, err := client.GetNotificationsExclude(ctx, &exclude, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Got %d notifications (excluding follows)\n", len(notifications))Example: Only Get Mentions and Replies
// Exclude everything except mentions
exclude := []string{"reblog", "favourite", "follow", "follow_request", "poll", "status", "update"}
mentions, err := client.GetNotificationsExclude(ctx, &exclude, nil)
if err != nil {
log.Fatal(err)
}func (c *Client) GetNotification(ctx context.Context, id ID) (*Notification, error)Returns a single notification by ID.
Parameters:
ctx - Context for cancellation/timeoutid - Notification ID to retrieveReturns: Notification object or error
Example:
notification, err := client.GetNotification(ctx, "123456")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Notification from @%s: %s\n",
notification.Account.Acct, notification.Type)func (c *Client) DismissNotification(ctx context.Context, id ID) errorDismisses a single notification.
Parameters:
ctx - Context for cancellation/timeoutid - Notification ID to dismissReturns: Error if operation fails
Example:
err := client.DismissNotification(ctx, "123456")
if err != nil {
log.Fatal(err)
}
fmt.Println("Notification dismissed")func (c *Client) ClearNotifications(ctx context.Context) errorClears all notifications for the current user.
Parameters:
ctx - Context for cancellation/timeoutReturns: Error if operation fails
Example:
err := client.ClearNotifications(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("All notifications cleared")Push subscriptions enable Web Push notifications for your application.
func (c *Client) AddPushSubscription(ctx context.Context, endpoint string, public ecdsa.PublicKey, shared []byte, alerts PushAlerts) (*PushSubscription, error)Adds a new push subscription.
Parameters:
ctx - Context for cancellation/timeoutendpoint - Push service endpoint URLpublic - ECDSA public key for encryptionshared - Shared authentication secretalerts - Alert type preferencesReturns: PushSubscription object or error
Example:
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
)
// Generate ECDSA key pair
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
// Generate shared secret
shared := make([]byte, 16)
_, err = rand.Read(shared)
if err != nil {
log.Fatal(err)
}
// Configure which notifications to push
alerts := mastodon.PushAlerts{
Follow: &mastodon.Sbool{true},
Favourite: &mastodon.Sbool{true},
Reblog: &mastodon.Sbool{true},
Mention: &mastodon.Sbool{true},
}
subscription, err := client.AddPushSubscription(
ctx,
"https://push.example.com/endpoint",
privateKey.PublicKey,
shared,
alerts,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Subscription created: %s\n", subscription.ID)func (c *Client) UpdatePushSubscription(ctx context.Context, alerts *PushAlerts) (*PushSubscription, error)Updates push subscription alert settings.
Parameters:
ctx - Context for cancellation/timeoutalerts - New alert type preferencesReturns: Updated PushSubscription or error
Example:
// Enable only mention and follow notifications
trueVal := mastodon.Sbool(true)
falseVal := mastodon.Sbool(false)
alerts := &mastodon.PushAlerts{
Follow: &trueVal,
Favourite: &falseVal,
Reblog: &falseVal,
Mention: &trueVal,
}
subscription, err := client.UpdatePushSubscription(ctx, alerts)
if err != nil {
log.Fatal(err)
}
fmt.Println("Push subscription updated")func (c *Client) GetPushSubscription(ctx context.Context) (*PushSubscription, error)Retrieves information about the active push subscription.
Parameters:
ctx - Context for cancellation/timeoutReturns: PushSubscription object or error
Example:
subscription, err := client.GetPushSubscription(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Subscription ID: %s\n", subscription.ID)
fmt.Printf("Endpoint: %s\n", subscription.Endpoint)
fmt.Printf("Mentions enabled: %v\n", subscription.Alerts.Mention)func (c *Client) RemovePushSubscription(ctx context.Context) errorRemoves the active push subscription.
Parameters:
ctx - Context for cancellation/timeoutReturns: Error if operation fails
Example:
err := client.RemovePushSubscription(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("Push subscription removed")func pollNotifications(client *mastodon.Client) {
ctx := context.Background()
var lastID mastodon.ID
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
pg := &mastodon.Pagination{}
if lastID != "" {
pg.SinceID = lastID
}
notifications, err := client.GetNotifications(ctx, pg)
if err != nil {
log.Printf("Error fetching notifications: %v", err)
continue
}
if len(notifications) > 0 {
lastID = notifications[0].ID
for _, notif := range notifications {
handleNotification(notif)
}
}
}
}
func handleNotification(n *mastodon.Notification) {
switch n.Type {
case "mention":
fmt.Printf("New mention from @%s\n", n.Account.Acct)
case "follow":
fmt.Printf("New follower: @%s\n", n.Account.Acct)
case "favourite":
fmt.Printf("@%s favourited your post\n", n.Account.Acct)
case "reblog":
fmt.Printf("@%s reblogged your post\n", n.Account.Acct)
}
}func getNotificationsByType(client *mastodon.Client, wantedType string) ([]*mastodon.Notification, error) {
ctx := context.Background()
allNotifications, err := client.GetNotifications(ctx, nil)
if err != nil {
return nil, err
}
var filtered []*mastodon.Notification
for _, notif := range allNotifications {
if notif.Type == wantedType {
filtered = append(filtered, notif)
}
}
return filtered, nil
}
// Usage
mentions, err := getNotificationsByType(client, "mention")
if err != nil {
log.Fatal(err)
}
fmt.Printf("You have %d mentions\n", len(mentions))func dismissOldNotifications(client *mastodon.Client, olderThan time.Duration) error {
ctx := context.Background()
cutoff := time.Now().Add(-olderThan)
notifications, err := client.GetNotifications(ctx, nil)
if err != nil {
return err
}
for _, notif := range notifications {
if notif.CreatedAt.Before(cutoff) {
err := client.DismissNotification(ctx, notif.ID)
if err != nil {
log.Printf("Failed to dismiss %s: %v", notif.ID, err)
}
}
}
return nil
}
// Usage: Dismiss notifications older than 7 days
err := dismissOldNotifications(client, 7*24*time.Hour)func getNotificationSummary(client *mastodon.Client) (map[string]int, error) {
ctx := context.Background()
notifications, err := client.GetNotifications(ctx, nil)
if err != nil {
return nil, err
}
summary := make(map[string]int)
for _, notif := range notifications {
summary[notif.Type]++
}
return summary, nil
}
// Usage
summary, err := getNotificationSummary(client)
if err != nil {
log.Fatal(err)
}
fmt.Println("Notification Summary:")
for notifType, count := range summary {
fmt.Printf(" %s: %d\n", notifType, count)
}pg := &mastodon.Pagination{Limit: 30}
notifications, err := client.GetNotifications(ctx, pg)Always check the notification type and handle appropriately:
switch notif.Type {
case "mention":
// Handle mention (has Status)
if notif.Status != nil {
processMessage(notif.Status)
}
case "follow":
// Handle follow (no Status)
addFollower(notif.Account)
}Some notification types don't have an associated status:
if notif.Status != nil {
fmt.Printf("Status: %s\n", notif.Status.Content)
}When polling notifications, use reasonable intervals:
ticker := time.NewTicker(30 * time.Second) // Not too frequentPush subscriptions may fail due to various reasons:
subscription, err := client.AddPushSubscription(ctx, endpoint, key, secret, alerts)
if err != nil {
if apiErr, ok := err.(*mastodon.APIError); ok {
if apiErr.StatusCode == 422 {
log.Printf("Invalid push subscription parameters")
}
}
return err
}See also: