diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java
index 9c700727f22da2a741058919133afcdd6c7646fa..1d50cd24f4740ffe3f879e79a9b04ac59d2856de 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.sharing.InvitationRequest;
 
 import javax.annotation.Nullable;
@@ -19,4 +20,8 @@ public class BlogInvitationRequest extends InvitationRequest<Blog> {
 				message, available, canBeOpened);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitBlogInvitatioRequest(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java
index cf3ac3ac8119cd34ef8b92af977c2c81090311c8..266382131b6b372ae21a4badd680e5a62b113cd6 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.sharing.InvitationResponse;
 
 @NotNullByDefault
@@ -16,4 +17,8 @@ public class BlogInvitationResponse extends InvitationResponse {
 				accept, shareableId);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitBlogInvitationResponse(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java
index 8d1028a9dc29d8d33260b1c12aecc432d72b260d..41f9919c55438a175dc91e4d2001fcb5f18b545e 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.sharing.InvitationRequest;
 
 import javax.annotation.Nullable;
@@ -21,4 +22,8 @@ public class ForumInvitationRequest extends InvitationRequest<Forum> {
 				message, available, canBeOpened);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitForumInvitationRequest(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java
index d0536ca9147309eb164d9397f164e7922c722349..1539ba20603231675f78e4d912d3b61bc1a15da9 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.sharing.InvitationResponse;
 
 import javax.annotation.concurrent.Immutable;
@@ -19,4 +20,8 @@ public class ForumInvitationResponse extends InvitationResponse {
 				accept, shareableId);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitForumInvitationResponse(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
index 91d52c255d8315ffa3d58ec2d8db823ffbc3c17d..3350ac1b68477d7b86b4d24f5ba2b226ab4eb526 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.messaging.PrivateRequest;
 
 import javax.annotation.Nullable;
@@ -28,4 +29,9 @@ public class IntroductionRequest extends PrivateRequest<Author> {
 	public boolean isContact() {
 		return contact;
 	}
+
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitIntroductionRequest(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
index 6ff9d883049240102cfcfd30f587b15adbbf682a..8e26d4bfb3a5441e007af085d22d8a144cb0b912 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.messaging.PrivateResponse;
 
 import javax.annotation.concurrent.Immutable;
@@ -35,4 +36,8 @@ public class IntroductionResponse extends PrivateResponse {
 		return ourRole == INTRODUCER;
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitIntroductionResponse(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java
index 619f0303b7a324998fdedd846209fa030cfe3290..b9f5110a688131fdf1b93ead6155f255ca4157f4 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java
@@ -54,4 +54,7 @@ public class PrivateMessageHeader {
 		return read;
 	}
 
+	public void accept(PrivateMessageVisitor v) {
+		v.visitPrivateMessageHeader(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageVisitor.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1e05974574676dd8013d5af67fbb238f956b8ca
--- /dev/null
+++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageVisitor.java
@@ -0,0 +1,31 @@
+package org.briarproject.briar.api.messaging;
+
+import org.briarproject.briar.api.blog.BlogInvitationRequest;
+import org.briarproject.briar.api.blog.BlogInvitationResponse;
+import org.briarproject.briar.api.forum.ForumInvitationRequest;
+import org.briarproject.briar.api.forum.ForumInvitationResponse;
+import org.briarproject.briar.api.introduction.IntroductionRequest;
+import org.briarproject.briar.api.introduction.IntroductionResponse;
+import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
+import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
+
+public interface PrivateMessageVisitor {
+
+	void visitPrivateMessageHeader(PrivateMessageHeader h);
+
+	void visitBlogInvitatioRequest(BlogInvitationRequest r);
+
+	void visitBlogInvitationResponse(BlogInvitationResponse r);
+
+	void visitForumInvitationRequest(ForumInvitationRequest r);
+
+	void visitForumInvitationResponse(ForumInvitationResponse r);
+
+	void visitGroupInvitationRequest(GroupInvitationRequest r);
+
+	void visitGroupInvitationResponse(GroupInvitationResponse r);
+
+	void visitIntroductionRequest(IntroductionRequest r);
+
+	void visitIntroductionResponse(IntroductionResponse r);
+}
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java
index 8067def68fb3b299bd3939dfbee13c186707f2c5..39c51f15999ea9a2b924311bb83824350e7c13c9 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.privategroup.PrivateGroup;
 import org.briarproject.briar.api.sharing.InvitationRequest;
 
@@ -22,4 +23,8 @@ public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
 				message, available, canBeOpened);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitGroupInvitationRequest(this);
+	}
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java
index 4b260eb625e4232a18177d267db7b60cecfbd666..e74b0c67fed352d6c7193b44d5dbce990caf61bb 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
 import org.briarproject.briar.api.sharing.InvitationResponse;
 
 import javax.annotation.concurrent.Immutable;
@@ -19,4 +20,8 @@ public class GroupInvitationResponse extends InvitationResponse {
 				accept, shareableId);
 	}
 
+	@Override
+	public void accept(PrivateMessageVisitor v) {
+		v.visitGroupInvitationResponse(this);
+	}
 }