diff --git a/server/server.go b/server/server.go
index 890690fb..a22ed7ba 100644
--- a/server/server.go
+++ b/server/server.go
@@ -114,13 +114,15 @@ var (
 )
 
 const (
-	firebaseControlTopic     = "~control"                // See Android if changed
-	firebasePollTopic        = "~poll"                   // See iOS if changed
-	emptyMessageBody         = "triggered"               // Used if message body is empty
-	newMessageBody           = "New message"             // Used in poll requests as generic message
-	defaultAttachmentMessage = "You received a file: %s" // Used if message body is empty, and there is an attachment
-	encodingBase64           = "base64"                  // Used mainly for binary UnifiedPush messages
-	jsonBodyBytesLimit       = 16384
+	firebaseControlTopic        = "~control"                // See Android if changed
+	firebasePollTopic           = "~poll"                   // See iOS if changed
+	emptyMessageBody            = "triggered"               // Used if message body is empty
+	newMessageBody              = "New message"             // Used in poll requests as generic message
+	defaultAttachmentMessage    = "You received a file: %s" // Used if message body is empty, and there is an attachment
+	encodingBase64              = "base64"                  // Used mainly for binary UnifiedPush messages
+	jsonBodyBytesLimit          = 16384
+	subscriberBilledTopicPrefix = "up_"
+	subscriberBilledValidity    = 12 * time.Hour
 )
 
 // WebSocket constants
diff --git a/server/topic.go b/server/topic.go
index fca5ee0a..6911ec0b 100644
--- a/server/topic.go
+++ b/server/topic.go
@@ -1,17 +1,21 @@
 package server
 
 import (
-	"heckel.io/ntfy/log"
 	"math/rand"
 	"sync"
+	"time"
+
+	"heckel.io/ntfy/log"
 )
 
 // topic represents a channel to which subscribers can subscribe, and publishers
 // can publish a message
 type topic struct {
-	ID          string
-	subscribers map[int]*topicSubscriber
-	mu          sync.Mutex
+	ID                 string
+	subscribers        map[int]*topicSubscriber
+	lastVisitor        *visitor
+	lastVisitorExpires time.Time
+	mu                 sync.Mutex
 }
 
 type topicSubscriber struct {
@@ -44,10 +48,30 @@ func (t *topic) Subscribe(s subscriber, visitor *visitor, cancel func()) int {
 	return subscriberID
 }
 
+func (t *topic) Stale() bool {
+	return t.getBillee() == nil
+}
+
+func (t *topic) getBillee() *visitor {
+	for _, this_subscriber := range t.subscribers {
+		return this_subscriber.visitor
+	}
+	if t.lastVisitor != nil && t.lastVisitorExpires.After(time.Now()) {
+		t.lastVisitor = nil
+	}
+	return t.lastVisitor
+
+}
+
 // Unsubscribe removes the subscription from the list of subscribers
 func (t *topic) Unsubscribe(id int) {
 	t.mu.Lock()
 	defer t.mu.Unlock()
+
+	if len(t.subscribers) == 1 {
+		t.lastVisitor = t.subscribers[id].visitor
+		t.lastVisitorExpires = time.Now().Add(subscriberBilledValidity)
+	}
 	delete(t.subscribers, id)
 }