diff --git a/browserid/lib/db.js b/browserid/lib/db.js
index de5548e2c1dec070f100c9ce7d219d4a4e23fa07..955d8da77d58601b62c9f3a1d42696b1b40c8da8 100644
--- a/browserid/lib/db.js
+++ b/browserid/lib/db.js
@@ -272,6 +272,15 @@ exports.checkAuth = function(email, cb) {
              });
 };
 
+function emailHasPubkey(email, pubkey, cb) {
+  db.execute(
+    'SELECT keys.key FROM keys, emails WHERE emails.address = ? AND keys.email = emails.id AND keys.key = ?',
+    [ email, pubkey ],
+    function(err, rows) {
+      cb(rows.length === 1);
+    });
+}
+
 /* a high level operation that attempts to sync a client's view with that of the
  * server.  email is the identity of the authenticated channel with the user,
  * identities is a map of email -> pubkey.
@@ -302,23 +311,34 @@ exports.getSyncResponse = function(email, identities, cb) {
         if (err) cb(err);
         else {
           var emails = [ ];
+          var keysToCheck = [ ];
           for (var i = 0; i < rows.length; i++) emails.push(rows[i].address);
 
           // #1
           for (var e in identities) {
             if (emails.indexOf(e) == -1) respBody.unknown_emails.push(e);
+            else keysToCheck.push(e);
           }
 
           // #2
           for (var e in emails) {
             e = emails[e];
             if (!identities.hasOwnProperty(e)) respBody.key_refresh.push(e);
+            
           }
 
-          // #3
-          // XXX todo
-
-          cb(undefined, respBody);
+          // #3 -- yes, this is sub-optimal in terms of performance.  when we
+          // move away from public keys this will be unnec.
+          var checked = 0;
+          keysToCheck.forEach(function(e) {
+            emailHasPubkey(e, identities[e], function(v) {
+              checked++;
+              if (!v) respBody.key_refresh.push(e);
+              if (checked === keysToCheck.length) {
+                cb(undefined, respBody);
+              }
+            });
+          });
         }
       });
   });
@@ -339,8 +359,6 @@ exports.pubkeysForEmail = function(identity, cb) {
     });
 };
 
-
-// FIXME: I'm not sure I'm using this data model properly
 exports.removeEmail = function(authenticated_email, email, cb) {
   // figure out the user, and remove Email only from addressed
   // linked to the authenticated email address
diff --git a/browserid/tests/db-test.js b/browserid/tests/db-test.js
index 45e19f3eb2d4c9a1a10888e536933f654f82a205..bd7afd9145bf30bb15b9d2d0f9c6a645b1c353be 100755
--- a/browserid/tests/db-test.js
+++ b/browserid/tests/db-test.js
@@ -53,7 +53,7 @@ suite.addBatch({
     topic: function() {
       return secret = db.stageUser({
         email: 'lloyd@nowhe.re',
-        pubkey: 'fakepublickey',
+        pubkey: 'fakepubkey',
         hash: 'fakepasswordhash'
       });
     },
@@ -116,7 +116,7 @@ suite.addBatch({
 suite.addBatch({
   "adding keys to email": {
     topic: function() {
-      db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepublickey2', this.callback);
+      db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey2', this.callback);
     },
     "works": function(r) {
       assert.isUndefined(r);
@@ -127,7 +127,7 @@ suite.addBatch({
 suite.addBatch({
   "adding multiple keys to email": {
     topic: function() {
-      db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepublickey3', this.callback);
+      db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey3', this.callback);
     },
     "works too": function(r) {
       assert.isUndefined(r);
@@ -190,12 +190,166 @@ suite.addBatch({
   }
 });
 
-// XXX: remaining APIs to test
-// exports.cancelAccount
 // exports.emailsBelongToSameAccount
+suite.addBatch({
+  "emails do belong to the same account": {
+    "is true": { 
+      topic: function() {
+        db.emailsBelongToSameAccount('lloyd@nowhe.re', 'lloyd@somewhe.re', this.callback);
+      },
+      "when they do": function(r) {
+        assert.isTrue(r);
+      }
+    },
+    "is false": { 
+      topic: function() {
+        db.emailsBelongToSameAccount('lloyd@anywhe.re', 'lloyd@somewhe.re', this.callback);
+      },
+      "when they don't": function(r) {
+        assert.isFalse(r);
+      }
+    }
+  }
+});
+
 // exports.getSyncResponse
+suite.addBatch({
+  "sync responses": {  
+    "are empty": {
+      topic: function() {
+        db.getSyncResponse('lloyd@nowhe.re',
+                           {
+                             'lloyd@nowhe.re': 'fakepubkey',
+                             'lloyd@somewhe.re': 'fakepubkey4'
+                           },
+                           this.callback);
+      },
+      "when everything is in sync": function (err, resp) {
+        assert.isUndefined(err);
+        assert.isArray(resp.unknown_emails);
+        assert.isArray(resp.key_refresh);
+        assert.strictEqual(resp.unknown_emails.length, 0);
+        assert.strictEqual(resp.key_refresh.length, 0);
+      }
+    },
+    "handles client unknown emails": {
+      topic: function() {
+        db.getSyncResponse('lloyd@nowhe.re',
+                           {
+                             'lloyd@nowhe.re': 'fakepubkey'
+                           },
+                           this.callback);
+      },
+      "by returning them in the key_refresh list": function (err, resp) {
+        assert.isUndefined(err);
+        assert.isArray(resp.unknown_emails);
+        assert.isArray(resp.key_refresh);
+        assert.strictEqual(resp.unknown_emails.length, 0);
+        assert.strictEqual(resp.key_refresh.length, 1);
+        assert.strictEqual(resp.key_refresh[0], 'lloyd@somewhe.re');
+      }
+    },
+    "handles server unknown emails": {
+      topic: function() {
+        db.getSyncResponse('lloyd@nowhe.re',
+                           {
+                             'lloyd@nowhe.re': 'fakepubkey',
+                             'lloyd@somewhe.re': 'fakepubkey4',
+                             'lloyd@anywhe.re': 'nofakepubkey',
+                           },
+                           this.callback);
+      },
+      "by returning them in the unknown_emails list": function (err, resp) {
+        assert.isUndefined(err);
+        assert.isArray(resp.unknown_emails);
+        assert.strictEqual(resp.unknown_emails.length, 1);
+        assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re');
+        assert.isArray(resp.key_refresh);
+        assert.strictEqual(resp.key_refresh.length, 0);
+      }
+    },
+    "handles server unknown keys": {
+      topic: function() {
+        db.getSyncResponse('lloyd@nowhe.re',
+                           {
+                             'lloyd@nowhe.re': 'fakepubkeyINVALID',
+                             'lloyd@somewhe.re': 'fakepubkey4'
+                           },
+                           this.callback);
+      },
+      "by returning them in the key_refresh list": function (err, resp) {
+        assert.isUndefined(err);
+        assert.isArray(resp.unknown_emails);
+        assert.strictEqual(resp.unknown_emails.length, 0);
+        assert.isArray(resp.key_refresh);
+        assert.strictEqual(resp.key_refresh.length, 1);
+        assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re');
+      }
+    },
+    "handle more than one case at a time": {
+      topic: function() {
+        db.getSyncResponse('lloyd@nowhe.re',
+                           {
+                             'lloyd@somewhe.re': 'fakepubkeyINVALID',
+                             'lloyd@anywhe.re': 'notreally'
+                           },
+                           this.callback);
+      },
+      "when everything is outta sync": function (err, resp) {
+        assert.isUndefined(err);
+        assert.isArray(resp.unknown_emails);
+        assert.strictEqual(resp.unknown_emails.length, 1);
+        assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re');
+
+        assert.isArray(resp.key_refresh);
+        assert.strictEqual(resp.key_refresh.length, 2);
+        assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re');
+        assert.strictEqual(resp.key_refresh[1], 'lloyd@somewhe.re');
+      }
+    }
+  }
+});
+
+suite.addBatch({
+  "removing an existing email": {
+    topic: function() {
+      db.removeEmail("lloyd@somewhe.re", "lloyd@nowhe.re", this.callback);
+    },
+    "returns no error": function(r) {
+      assert.isUndefined(r);
+    },
+    "causes emailKnown": {
+      topic: function() {
+        db.emailKnown('lloyd@nowhe.re', this.callback);
+      },
+      "to return false": function (r) {
+        assert.strictEqual(r, false);
+      }
+    }
+  }
+});
+
+suite.addBatch({
+  "canceling an account": {
+    topic: function() {
+      db.cancelAccount("lloyd@somewhe.re", this.callback);
+    },
+    "returns no error": function(r) {
+      assert.isUndefined(r);
+    },
+    "causes emailKnown": {
+      topic: function() {
+        db.emailKnown('lloyd@somewhe.re', this.callback);
+      },
+      "to return false": function (r) {
+        assert.strictEqual(r, false);
+      }
+    }
+  }
+});
+
+// exports.cancelAccount
 // exports.removeEmail
-// exports.stageEmail
 
 suite.addBatch({
   "remove the database file": {