diff --git a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
index 9f61e34cb25af9f7ef07bd2d01c3f474f913108a..80e8c28e9322d53c29877532159f1011e7625928 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
@@ -142,9 +142,9 @@ EventListener {
 						try {
 							ContactId id = c.getId();
 							GroupId inbox =
-									messagingManager.getInboxGroupId(id);
+									messagingManager.getConversationId(id);
 							Collection<MessageHeader> headers =
-									messagingManager.getInboxMessageHeaders(id);
+									messagingManager.getMessageHeaders(id);
 							displayContact(c, inbox, headers);
 						} catch (NoSuchContactException e) {
 							// Continue
@@ -294,7 +294,7 @@ EventListener {
 				try {
 					long now = System.currentTimeMillis();
 					Collection<MessageHeader> headers =
-							messagingManager.getInboxMessageHeaders(c);
+							messagingManager.getMessageHeaders(c);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Partial load took " + duration + " ms");
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 662ada73878ce6573e471424a182a8ca1e31c011..804e2ce356331d35b1005a7e8184f0f6f21cfe40 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -39,11 +39,11 @@ import org.briarproject.api.event.MessagesAckedEvent;
 import org.briarproject.api.event.MessagesSentEvent;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.messaging.MessagingManager;
+import org.briarproject.api.messaging.PrivateConversation;
+import org.briarproject.api.messaging.PrivateMessageFactory;
 import org.briarproject.api.plugins.ConnectionRegistry;
-import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
-import org.briarproject.api.sync.MessageFactory;
 import org.briarproject.api.sync.MessageHeader;
 import org.briarproject.api.sync.MessageHeader.State;
 import org.briarproject.api.sync.MessageId;
@@ -93,11 +93,11 @@ implements EventListener, OnClickListener, OnItemClickListener {
 	@Inject private volatile ContactManager contactManager;
 	@Inject private volatile MessagingManager messagingManager;
 	@Inject private volatile EventBus eventBus;
-	@Inject private volatile MessageFactory messageFactory;
+	@Inject private volatile PrivateMessageFactory privateMessageFactory;
 	private volatile ContactId contactId = null;
 	private volatile String contactName = null;
 	private volatile GroupId groupId = null;
-	private volatile Group group = null;
+	private volatile PrivateConversation conversation = null;
 	private volatile AuthorId localAuthorId = null;
 	private volatile boolean connected;
 
@@ -147,7 +147,7 @@ implements EventListener, OnClickListener, OnItemClickListener {
 
 		content = (EditText) findViewById(R.id.contentView);
 		sendButton = (ImageButton) findViewById(R.id.sendButton);
-		sendButton.setEnabled(false); // Enabled after loading the group
+		sendButton.setEnabled(false); // Enabled after loading the conversation
 		sendButton.setOnClickListener(this);
 	}
 
@@ -167,12 +167,12 @@ implements EventListener, OnClickListener, OnItemClickListener {
 					Contact contact = contactManager.getContact(contactId);
 					contactName = contact.getAuthor().getName();
 					localAuthorId = contact.getLocalAuthorId();
-					groupId = messagingManager.getInboxGroupId(contactId);
-					group = messagingManager.getGroup(groupId);
+					groupId = messagingManager.getConversationId(contactId);
+					conversation = messagingManager.getConversation(groupId);
 					connected = connectionRegistry.isConnected(contactId);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO)) {
-						LOG.info("Loading contact and group took "
+						LOG.info("Loading contact and conversation took "
 								+ duration + " ms");
 					}
 					displayContactDetails();
@@ -210,7 +210,7 @@ implements EventListener, OnClickListener, OnItemClickListener {
 				try {
 					long now = System.currentTimeMillis();
 					Collection<MessageHeader> headers =
-							messagingManager.getInboxMessageHeaders(contactId);
+							messagingManager.getMessageHeaders(contactId);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Loading headers took " + duration + " ms");
@@ -424,8 +424,8 @@ implements EventListener, OnClickListener, OnItemClickListener {
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
 				try {
-					Message m = messageFactory.createAnonymousMessage(null,
-							group, "text/plain", timestamp, body);
+					Message m = privateMessageFactory.createPrivateMessage(null,
+							conversation, "text/plain", timestamp, body);
 					storeMessage(m);
 				} catch (GeneralSecurityException e) {
 					throw new RuntimeException(e);
diff --git a/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java b/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
index 44dc87dc89e6170125e11d86bf81e369c3cc5969..74623463e43d026a5aa4d332bf6034d284eb6aba 100644
--- a/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/WritePrivateMessageActivity.java
@@ -24,10 +24,10 @@ import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.messaging.MessagingManager;
-import org.briarproject.api.sync.Group;
+import org.briarproject.api.messaging.PrivateConversation;
+import org.briarproject.api.messaging.PrivateMessageFactory;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
-import org.briarproject.api.sync.MessageFactory;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.util.StringUtils;
 
@@ -65,21 +65,20 @@ implements OnClickListener {
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile IdentityManager identityManager;
 	@Inject private volatile MessagingManager messagingManager;
-	@Inject private volatile MessageFactory messageFactory;
-	private volatile String contactName = null;
+	@Inject private volatile PrivateMessageFactory privateMessageFactory;
 	private volatile GroupId groupId = null;
 	private volatile AuthorId localAuthorId = null;
 	private volatile MessageId parentId = null;
 	private volatile long minTimestamp = -1;
 	private volatile LocalAuthor localAuthor = null;
-	private volatile Group group = null;
+	private volatile PrivateConversation conversation = null;
 
 	@Override
 	public void onCreate(Bundle state) {
 		super.onCreate(state);
 
 		Intent i = getIntent();
-		contactName = i.getStringExtra("briar.CONTACT_NAME");
+		String contactName = i.getStringExtra("briar.CONTACT_NAME");
 		if (contactName == null) throw new IllegalStateException();
 		setTitle(contactName);
 		byte[] b = i.getByteArrayExtra("briar.GROUP_ID");
@@ -118,7 +117,7 @@ implements OnClickListener {
 		sendButton.setId(2);
 		sendButton.setBackgroundResource(0);
 		sendButton.setImageResource(R.drawable.social_send_now);
-		sendButton.setEnabled(false); // Enabled after loading the group
+		sendButton.setEnabled(false); // Enabled after loading the conversation
 		sendButton.setOnClickListener(this);
 		RelativeLayout.LayoutParams right = CommonLayoutParams.relative();
 		right.addRule(ALIGN_PARENT_RIGHT);
@@ -140,16 +139,17 @@ implements OnClickListener {
 	@Override
 	public void onResume() {
 		super.onResume();
-		if (localAuthor == null || group == null) loadAuthorAndGroup();
+		if (localAuthor == null || conversation == null)
+			loadAuthorAndConversation();
 	}
 
-	private void loadAuthorAndGroup() {
+	private void loadAuthorAndConversation() {
 		runOnDbThread(new Runnable() {
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
 					localAuthor = identityManager.getLocalAuthor(localAuthorId);
-					group = messagingManager.getGroup(groupId);
+					conversation = messagingManager.getConversation(groupId);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Load took " + duration + " ms");
@@ -192,8 +192,9 @@ implements OnClickListener {
 				long timestamp = System.currentTimeMillis();
 				timestamp = Math.max(timestamp, minTimestamp);
 				try {
-					Message m = messageFactory.createAnonymousMessage(parentId,
-							group, "text/plain", timestamp, body);
+					Message m = privateMessageFactory.createPrivateMessage(
+							parentId, conversation, "text/plain", timestamp,
+							body);
 					storeMessage(m);
 				} catch (GeneralSecurityException e) {
 					throw new RuntimeException(e);
diff --git a/briar-api/src/org/briarproject/api/messaging/MessagingManager.java b/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
index a306d6d753c6989a10e5506a6b61095970b3e16a..afdcc1320064f3e980223864ed301f5d523a9c46 100644
--- a/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
+++ b/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
@@ -2,7 +2,6 @@ package org.briarproject.api.messaging;
 
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageHeader;
@@ -12,43 +11,35 @@ import java.util.Collection;
 
 public interface MessagingManager {
 
-	/**
-	 * Subscribes to a group, or returns false if the user already has the
-	 * maximum number of public subscriptions.
-	 */
-	boolean addGroup(Group g) throws DbException;
-
-	/** Stores a local message. */
+	/** Stores a local private message. */
 	void addLocalMessage(Message m) throws DbException;
 
-	/** Returns the group with the given ID, if the user subscribes to it. */
-	Group getGroup(GroupId g) throws DbException;
-
+	/** Returns the private conversation with the given ID. */
+	PrivateConversation getConversation(GroupId g) throws DbException;
 
 	/**
-	 * Returns the ID of the inbox group for the given contact, or null if no
-	 * inbox group has been set.
+	 * Returns the ID of the private conversation with the given contact, or
+	 * null if no private conversation ID has been set.
 	 */
-	GroupId getInboxGroupId(ContactId c) throws DbException;
+	GroupId getConversationId(ContactId c) throws DbException;
 
 	/**
-	 * Returns the headers of all messages in the inbox group for the given
-	 * contact, or null if no inbox group has been set.
+	 * Returns the headers of all messages in the private conversation with the
+	 * given contact, or null if no private conversation ID has been set.
 	 */
-	Collection<MessageHeader> getInboxMessageHeaders(ContactId c)
+	Collection<MessageHeader> getMessageHeaders(ContactId c)
 			throws DbException;
 
-	/** Returns the body of the message with the given ID. */
+	/** Returns the body of the private message with the given ID. */
 	byte[] getMessageBody(MessageId m) throws DbException;
 
 	/**
-	 * Makes a group visible to the given contact, adds it to the contact's
-	 * subscriptions, and sets it as the inbox group for the contact.
+	 * Makes a private conversation visible to the given contact, adds it to
+	 * the contact's subscriptions, and sets it as the private conversation for
+	 * the contact.
 	 */
-	void setInboxGroup(ContactId c, Group g) throws DbException;
+	void setConversation(ContactId c, PrivateConversation p) throws DbException;
 
-	/**
-	 * Marks a message as read or unread.
-	 */
+	/** Marks a private message as read or unread. */
 	void setReadFlag(MessageId m, boolean read) throws DbException;
 }
diff --git a/briar-api/src/org/briarproject/api/messaging/PrivateConversation.java b/briar-api/src/org/briarproject/api/messaging/PrivateConversation.java
new file mode 100644
index 0000000000000000000000000000000000000000..a94d183550eda4f4b9f00a9e2b327aceda6ea653
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/messaging/PrivateConversation.java
@@ -0,0 +1,8 @@
+package org.briarproject.api.messaging;
+
+import org.briarproject.api.sync.GroupId;
+
+public interface PrivateConversation {
+
+	GroupId getId();
+}
diff --git a/briar-api/src/org/briarproject/api/messaging/PrivateMessageFactory.java b/briar-api/src/org/briarproject/api/messaging/PrivateMessageFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..09c5102c800545cb1aa82526b2139fe60e8c63e3
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/messaging/PrivateMessageFactory.java
@@ -0,0 +1,15 @@
+package org.briarproject.api.messaging;
+
+import org.briarproject.api.sync.Message;
+import org.briarproject.api.sync.MessageId;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+public interface PrivateMessageFactory {
+
+	Message createPrivateMessage(MessageId parent,
+			PrivateConversation conversation, String contentType,
+			long timestamp, byte[] body) throws IOException,
+			GeneralSecurityException;
+}
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index b3929a1ed79085d3c226a00c3e83e16e47633ff8..e0c1c793b0359843c3f2d592d2fab20c8c1acafc 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -6,7 +6,7 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.messaging.MessagingManager;
-import org.briarproject.api.sync.Group;
+import org.briarproject.api.messaging.PrivateConversation;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageHeader;
@@ -14,6 +14,7 @@ import org.briarproject.api.sync.MessageId;
 
 import java.util.Collection;
 
+// Temporary facade during sync protocol refactoring
 class MessagingManagerImpl implements MessagingManager {
 
 	private final DatabaseComponent db;
@@ -23,28 +24,23 @@ class MessagingManagerImpl implements MessagingManager {
 		this.db = db;
 	}
 
-	@Override
-	public boolean addGroup(Group g) throws DbException {
-		return db.addGroup(g);
-	}
-
 	@Override
 	public void addLocalMessage(Message m) throws DbException {
 		db.addLocalMessage(m);
 	}
 
 	@Override
-	public Group getGroup(GroupId g) throws DbException {
-		return db.getGroup(g);
+	public PrivateConversation getConversation(GroupId g) throws DbException {
+		return new PrivateConversationImpl(db.getGroup(g));
 	}
 
 	@Override
-	public GroupId getInboxGroupId(ContactId c) throws DbException {
+	public GroupId getConversationId(ContactId c) throws DbException {
 		return db.getInboxGroupId(c);
 	}
 
 	@Override
-	public Collection<MessageHeader> getInboxMessageHeaders(ContactId c)
+	public Collection<MessageHeader> getMessageHeaders(ContactId c)
 			throws DbException {
 		return db.getInboxMessageHeaders(c);
 	}
@@ -55,8 +51,9 @@ class MessagingManagerImpl implements MessagingManager {
 	}
 
 	@Override
-	public void setInboxGroup(ContactId c, Group g) throws DbException {
-		db.setInboxGroup(c, g);
+	public void setConversation(ContactId c, PrivateConversation p)
+			throws DbException {
+		db.setInboxGroup(c, ((PrivateConversationImpl) p).getGroup());
 	}
 
 	@Override
diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java
index 762e9c76dc5037ecf82caad660554fd2062b913b..6134939932f75da6f1049aa589a547a680ee6bef 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingModule.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java
@@ -3,11 +3,13 @@ package org.briarproject.messaging;
 import com.google.inject.AbstractModule;
 
 import org.briarproject.api.messaging.MessagingManager;
+import org.briarproject.api.messaging.PrivateMessageFactory;
 
 public class MessagingModule extends AbstractModule {
 
 	@Override
 	protected void configure() {
 		bind(MessagingManager.class).to(MessagingManagerImpl.class);
+		bind(PrivateMessageFactory.class).to(PrivateMessageFactoryImpl.class);
 	}
 }
diff --git a/briar-core/src/org/briarproject/messaging/PrivateConversationImpl.java b/briar-core/src/org/briarproject/messaging/PrivateConversationImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..febb0308c76438076895c739945135ed880cf8b7
--- /dev/null
+++ b/briar-core/src/org/briarproject/messaging/PrivateConversationImpl.java
@@ -0,0 +1,35 @@
+package org.briarproject.messaging;
+
+import org.briarproject.api.messaging.PrivateConversation;
+import org.briarproject.api.sync.Group;
+import org.briarproject.api.sync.GroupId;
+
+// Temporary facade during sync protocol refactoring
+class PrivateConversationImpl implements PrivateConversation {
+
+	private final Group group;
+
+	PrivateConversationImpl(Group group) {
+		this.group = group;
+	}
+
+	@Override
+	public GroupId getId() {
+		return group.getId();
+	}
+
+	Group getGroup() {
+		return group;
+	}
+
+	@Override
+	public int hashCode() {
+		return group.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		return o instanceof PrivateConversationImpl
+				&& group.equals(((PrivateConversationImpl) o).group);
+	}
+}
diff --git a/briar-core/src/org/briarproject/messaging/PrivateMessageFactoryImpl.java b/briar-core/src/org/briarproject/messaging/PrivateMessageFactoryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..71098bd41a254229e71e05b1a6ad1d8862b15b77
--- /dev/null
+++ b/briar-core/src/org/briarproject/messaging/PrivateMessageFactoryImpl.java
@@ -0,0 +1,33 @@
+package org.briarproject.messaging;
+
+import com.google.inject.Inject;
+
+import org.briarproject.api.messaging.PrivateConversation;
+import org.briarproject.api.messaging.PrivateMessageFactory;
+import org.briarproject.api.sync.Message;
+import org.briarproject.api.sync.MessageFactory;
+import org.briarproject.api.sync.MessageId;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+// Temporary facade during sync protocol refactoring
+class PrivateMessageFactoryImpl implements PrivateMessageFactory {
+
+	private final MessageFactory messageFactory;
+
+	@Inject
+	PrivateMessageFactoryImpl(MessageFactory messageFactory) {
+		this.messageFactory = messageFactory;
+	}
+
+	@Override
+	public Message createPrivateMessage(MessageId parent,
+			PrivateConversation conversation, String contentType,
+			long timestamp, byte[] body)
+			throws IOException, GeneralSecurityException {
+		return messageFactory.createAnonymousMessage(parent,
+				((PrivateConversationImpl) conversation).getGroup(),
+				contentType, timestamp, body);
+	}
+}