diff --git a/scripts/basic.css b/scripts/basic.css
deleted file mode 100644
index 6411570ee6ef0c6eab9ab642fc70950a50cae5d2..0000000000000000000000000000000000000000
--- a/scripts/basic.css
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * basic.css
- * ~~~~~~~~~
- *
- * Sphinx stylesheet -- basic theme.
- *
- * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-/* -- main layout ----------------------------------------------------------- */
-
-div.clearer {
-    clear: both;
-}
-
-/* -- relbar ---------------------------------------------------------------- */
-
-div.related {
-    width: 100%;
-    font-size: 90%;
-}
-
-div.related h3 {
-    display: none;
-}
-
-div.related ul {
-    margin: 0;
-    padding: 0 0 0 10px;
-    list-style: none;
-}
-
-div.related li {
-    display: inline;
-}
-
-div.related li.right {
-    float: right;
-    margin-right: 5px;
-}
-
-/* -- sidebar --------------------------------------------------------------- */
-
-div.sphinxsidebarwrapper {
-    padding: 10px 5px 0 10px;
-}
-
-div.sphinxsidebar {
-    float: left;
-    width: 230px;
-    margin-left: -100%;
-    font-size: 90%;
-}
-
-div.sphinxsidebar ul {
-    list-style: none;
-}
-
-div.sphinxsidebar ul ul,
-div.sphinxsidebar ul.want-points {
-    margin-left: 20px;
-    list-style: square;
-}
-
-div.sphinxsidebar ul ul {
-    margin-top: 0;
-    margin-bottom: 0;
-}
-
-div.sphinxsidebar form {
-    margin-top: 10px;
-}
-
-div.sphinxsidebar input {
-    border: 1px solid #98dbcc;
-    font-family: sans-serif;
-    font-size: 1em;
-}
-
-img {
-    border: 0;
-}
-
-/* -- search page ----------------------------------------------------------- */
-
-ul.search {
-    margin: 10px 0 0 20px;
-    padding: 0;
-}
-
-ul.search li {
-    padding: 5px 0 5px 20px;
-    background-image: url(file.png);
-    background-repeat: no-repeat;
-    background-position: 0 7px;
-}
-
-ul.search li a {
-    font-weight: bold;
-}
-
-ul.search li div.context {
-    color: #888;
-    margin: 2px 0 0 30px;
-    text-align: left;
-}
-
-ul.keywordmatches li.goodmatch a {
-    font-weight: bold;
-}
-
-/* -- index page ------------------------------------------------------------ */
-
-table.contentstable {
-    width: 90%;
-}
-
-table.contentstable p.biglink {
-    line-height: 150%;
-}
-
-a.biglink {
-    font-size: 1.3em;
-}
-
-span.linkdescr {
-    font-style: italic;
-    padding-top: 5px;
-    font-size: 90%;
-}
-
-/* -- general index --------------------------------------------------------- */
-
-table.indextable {
-    width: 100%;
-}
-
-table.indextable td {
-    text-align: left;
-    vertical-align: top;
-}
-
-table.indextable dl, table.indextable dd {
-    margin-top: 0;
-    margin-bottom: 0;
-}
-
-table.indextable tr.pcap {
-    height: 10px;
-}
-
-table.indextable tr.cap {
-    margin-top: 10px;
-    background-color: #f2f2f2;
-}
-
-img.toggler {
-    margin-right: 3px;
-    margin-top: 3px;
-    cursor: pointer;
-}
-
-div.modindex-jumpbox {
-    border-top: 1px solid #ddd;
-    border-bottom: 1px solid #ddd;
-    margin: 1em 0 1em 0;
-    padding: 0.4em;
-}
-
-div.genindex-jumpbox {
-    border-top: 1px solid #ddd;
-    border-bottom: 1px solid #ddd;
-    margin: 1em 0 1em 0;
-    padding: 0.4em;
-}
-
-/* -- general body styles --------------------------------------------------- */
-
-a.headerlink {
-    visibility: hidden;
-}
-
-h1:hover > a.headerlink,
-h2:hover > a.headerlink,
-h3:hover > a.headerlink,
-h4:hover > a.headerlink,
-h5:hover > a.headerlink,
-h6:hover > a.headerlink,
-dt:hover > a.headerlink {
-    visibility: visible;
-}
-
-div.document p.caption {
-    text-align: inherit;
-}
-
-div.document td {
-    text-align: left;
-}
-
-.field-list ul {
-    padding-left: 1em;
-}
-
-.first {
-    margin-top: 0 !important;
-}
-
-p.rubric {
-    margin-top: 30px;
-    font-weight: bold;
-}
-
-.align-left {
-    text-align: left;
-}
-
-.align-center {
-    clear: both;
-    text-align: center;
-}
-
-.align-right {
-    text-align: right;
-}
-
-/* -- sidebars -------------------------------------------------------------- */
-
-div.sidebar {
-    margin: 0 0 0.5em 1em;
-    border: 1px solid #ddb;
-    padding: 7px 7px 0 7px;
-    background-color: #ffe;
-    width: 40%;
-    float: right;
-}
-
-p.sidebar-title {
-    font-weight: bold;
-}
-
-/* -- topics ---------------------------------------------------------------- */
-
-div.topic {
-    border: 1px solid #ccc;
-    padding: 7px 7px 0 7px;
-    margin: 10px 0 10px 0;
-}
-
-p.topic-title {
-    font-size: 1.1em;
-    font-weight: bold;
-    margin-top: 10px;
-}
-
-/* -- admonitions ----------------------------------------------------------- */
-
-div.admonition {
-    margin-top: 10px;
-    margin-bottom: 10px;
-    padding: 7px;
-}
-
-div.admonition dt {
-    font-weight: bold;
-}
-
-div.admonition dl {
-    margin-bottom: 0;
-}
-
-p.admonition-title {
-    margin: 0px 10px 5px 0px;
-    font-weight: bold;
-}
-
-div.document p.centered {
-    text-align: center;
-    margin-top: 25px;
-}
-
-/* -- tables ---------------------------------------------------------------- */
-
-table.docutils {
-    border: 0;
-    border-collapse: collapse;
-}
-
-table.docutils td, table.docutils th {
-    padding: 1px 8px 1px 5px;
-    border-top: 0;
-    border-left: 0;
-    border-right: 0;
-    border-bottom: 1px solid #aaa;
-}
-
-table.field-list td, table.field-list th {
-    border: 0 !important;
-}
-
-table.footnote td, table.footnote th {
-    border: 0 !important;
-}
-
-th {
-    text-align: left;
-    padding-right: 5px;
-}
-
-table.citation {
-    border-left: solid 1px gray;
-    margin-left: 1px;
-}
-
-table.citation td {
-    border-bottom: none;
-}
-
-/* -- other body styles ----------------------------------------------------- */
-
-ol.arabic {
-    list-style: decimal;
-}
-
-ol.loweralpha {
-    list-style: lower-alpha;
-}
-
-ol.upperalpha {
-    list-style: upper-alpha;
-}
-
-ol.lowerroman {
-    list-style: lower-roman;
-}
-
-ol.upperroman {
-    list-style: upper-roman;
-}
-
-dl {
-    margin-bottom: 15px;
-}
-
-dd p {
-    margin-top: 0px;
-}
-
-dd ul, dd table {
-    margin-bottom: 10px;
-}
-
-dd {
-    margin-top: 3px;
-    margin-bottom: 10px;
-    margin-left: 30px;
-}
-
-dt:target, .highlighted {
-    background-color: #fbe54e;
-}
-
-dl.glossary dt {
-    font-weight: bold;
-    font-size: 1.1em;
-}
-
-.field-list ul {
-    margin: 0;
-    padding-left: 1em;
-}
-
-.field-list p {
-    margin: 0;
-}
-
-.refcount {
-    color: #060;
-}
-
-.optional {
-    font-size: 1.3em;
-}
-
-.versionmodified {
-    font-style: italic;
-}
-
-.system-message {
-    background-color: #fda;
-    padding: 5px;
-    border: 3px solid red;
-}
-
-.footnote:target  {
-    background-color: #ffa
-}
-
-.line-block {
-    display: block;
-    margin-top: 1em;
-    margin-bottom: 1em;
-}
-
-.line-block .line-block {
-    margin-top: 0;
-    margin-bottom: 0;
-    margin-left: 1.5em;
-}
-
-.guilabel, .menuselection {
-    font-family: sans-serif;
-}
-
-.accelerator {
-    text-decoration: underline;
-}
-
-.classifier {
-    font-style: oblique;
-}
-
-/* -- code displays --------------------------------------------------------- */
-
-pre {
-    overflow: auto;
-}
-
-td.linenos pre {
-    padding: 5px 0px;
-    border: 0;
-    background-color: transparent;
-    color: #aaa;
-}
-
-table.highlighttable {
-    margin-left: 0.5em;
-}
-
-table.highlighttable td {
-    padding: 0 0.5em 0 0.5em;
-}
-
-tt.descname {
-    background-color: transparent;
-    font-weight: bold;
-    font-size: 1.2em;
-}
-
-tt.descclassname {
-    background-color: transparent;
-}
-
-tt.xref, a tt {
-    background-color: transparent;
-    font-weight: bold;
-}
-
-h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
-    background-color: transparent;
-}
-
-.viewcode-link {
-    float: right;
-}
-
-.viewcode-back {
-    float: right;
-    font-family: sans-serif;
-}
-
-div.viewcode-block:target {
-    margin: -1px -10px;
-    padding: 0 10px;
-}
-
-/* -- math display ---------------------------------------------------------- */
-
-img.math {
-    vertical-align: middle;
-}
-
-div.document div.math p {
-    text-align: center;
-}
-
-span.eqno {
-    float: right;
-}
-
-/* -- printout stylesheet --------------------------------------------------- */
-
-@media print {
-    div.document,
-    div.documentwrapper,
-    div.bodywrapper {
-        margin: 0 !important;
-        width: 100%;
-    }
-
-    div.sphinxsidebar,
-    div.related,
-    div.footer,
-    #top-link {
-        display: none;
-    }
-}
-
diff --git a/scripts/gendoc.sh b/scripts/gendoc.sh
deleted file mode 100755
index 64aff3155e3abbf9d75f01f7d9bdd0a1ac57316f..0000000000000000000000000000000000000000
--- a/scripts/gendoc.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-MATRIXDOTORG=$HOME/workspace/matrix.org
-
-rst2html-2.7.py --stylesheet=basic.css,nature.css ../docs/specification.rst > $MATRIXDOTORG/docs/spec/index.html
-rst2html-2.7.py --stylesheet=basic.css,nature.css ../docs/client-server/howto.rst > $MATRIXDOTORG/docs/howtos/client-server.html
-
-perl -pi -e 's#<head>#<head><link rel="stylesheet" href="/site.css">#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
-
-perl -pi -e 's#<body>#<body><div id="header"><div id="headerContent">&nbsp;</div></div><div id="page"><div id="wrapper"><div style="text-align: center; padding: 40px;"><a href="/"><img src="/matrix.png" width="305" height="130" alt="[matrix]"/></a></div>#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
-
-perl -pi -e 's#</body>#</div></div><div id="footer"><div id="footerContent">&copy 2014 Matrix.org</div></div></body>#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
-
-scp -r $MATRIXDOTORG/docs matrix@ldc-prd-matrix-001:/sites/matrix
\ No newline at end of file
diff --git a/scripts/nature.css b/scripts/nature.css
deleted file mode 100644
index b8147f10ee15bec309e0d7b660d1f962978b76cc..0000000000000000000000000000000000000000
--- a/scripts/nature.css
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * nature.css_t
- * ~~~~~~~~~~~~
- *
- * Sphinx stylesheet -- nature theme.
- *
- * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
- 
-/* -- page layout ----------------------------------------------------------- */
- 
-body {
-    font-family: Arial, sans-serif;
-    font-size: 100%;
-    /*background-color: #111;*/
-    color: #555;
-    margin: 0;
-    padding: 0;
-}
-
-div.documentwrapper {
-    float: left;
-    width: 100%;
-}
-
-div.bodywrapper {
-    margin: 0 0 0 230px;
-}
-
-hr {
-    border: 1px solid #B1B4B6;
-}
- 
-/*
-div.document {
-    background-color: #eee;
-}
-*/
- 
-div.document {
-    background-color: #ffffff;
-    color: #3E4349;
-    padding: 0 30px 30px 30px;
-    font-size: 0.9em;
-}
- 
-div.footer {
-    color: #555;
-    width: 100%;
-    padding: 13px 0;
-    text-align: center;
-    font-size: 75%;
-}
- 
-div.footer a {
-    color: #444;
-    text-decoration: underline;
-}
- 
-div.related {
-    background-color: #6BA81E;
-    line-height: 32px;
-    color: #fff;
-    text-shadow: 0px 1px 0 #444;
-    font-size: 0.9em;
-}
- 
-div.related a {
-    color: #E2F3CC;
-}
- 
-div.sphinxsidebar {
-    font-size: 0.75em;
-    line-height: 1.5em;
-}
-
-div.sphinxsidebarwrapper{
-    padding: 20px 0;
-}
- 
-div.sphinxsidebar h3,
-div.sphinxsidebar h4 {
-    font-family: Arial, sans-serif;
-    color: #222;
-    font-size: 1.2em;
-    font-weight: normal;
-    margin: 0;
-    padding: 5px 10px;
-    background-color: #ddd;
-    text-shadow: 1px 1px 0 white
-}
-
-div.sphinxsidebar h4{
-    font-size: 1.1em;
-}
- 
-div.sphinxsidebar h3 a {
-    color: #444;
-}
- 
- 
-div.sphinxsidebar p {
-    color: #888;
-    padding: 5px 20px;
-}
- 
-div.sphinxsidebar p.topless {
-}
- 
-div.sphinxsidebar ul {
-    margin: 10px 20px;
-    padding: 0;
-    color: #000;
-}
- 
-div.sphinxsidebar a {
-    color: #444;
-}
- 
-div.sphinxsidebar input {
-    border: 1px solid #ccc;
-    font-family: sans-serif;
-    font-size: 1em;
-}
-
-div.sphinxsidebar input[type=text]{
-    margin-left: 20px;
-}
- 
-/* -- body styles ----------------------------------------------------------- */
- 
-a {
-    color: #005B81;
-    text-decoration: none;
-}
- 
-a:hover {
-    color: #E32E00;
-    text-decoration: underline;
-}
- 
-div.document h1,
-div.document h2,
-div.document h3,
-div.document h4,
-div.document h5,
-div.document h6 {
-    font-family: Arial, sans-serif;
-    background-color: #BED4EB;
-    font-weight: normal;
-    color: #212224;
-    margin: 30px 0px 10px 0px;
-    padding: 5px 0 5px 10px;
-    text-shadow: 0px 1px 0 white
-}
- 
-div.document h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
-div.document h2 { font-size: 150%; background-color: #C8D5E3; }
-div.document h3 { font-size: 120%; background-color: #D8DEE3; }
-div.document h4 { font-size: 110%; background-color: #D8DEE3; }
-div.document h5 { font-size: 100%; background-color: #D8DEE3; }
-div.document h6 { font-size: 100%; background-color: #D8DEE3; }
- 
-a.headerlink {
-    color: #c60f0f;
-    font-size: 0.8em;
-    padding: 0 4px 0 4px;
-    text-decoration: none;
-}
- 
-a.headerlink:hover {
-    background-color: #c60f0f;
-    color: white;
-}
- 
-div.document p, div.document dd, div.document li {
-    line-height: 1.5em;
-}
- 
-div.admonition p.admonition-title + p {
-    display: inline;
-}
-
-div.highlight{
-    background-color: white;
-}
-
-div.note {
-    background-color: #eee;
-    border: 1px solid #ccc;
-}
- 
-div.seealso {
-    background-color: #ffc;
-    border: 1px solid #ff6;
-}
- 
-div.topic {
-    background-color: #eee;
-}
- 
-div.warning {
-    background-color: #ffe4e4;
-    border: 1px solid #f66;
-}
- 
-p.admonition-title {
-    display: inline;
-}
- 
-p.admonition-title:after {
-    content: ":";
-}
- 
-pre {
-    padding: 10px;
-    background-color: White;
-    color: #222;
-    line-height: 1.2em;
-    border: 1px solid #C6C9CB;
-    font-size: 1.1em;
-    margin: 1.5em 0 1.5em 0;
-    -webkit-box-shadow: 1px 1px 1px #d8d8d8;
-    -moz-box-shadow: 1px 1px 1px #d8d8d8;
-}
- 
-tt {
-    background-color: #ecf0f3;
-    color: #222;
-    /* padding: 1px 2px; */
-    font-size: 1.1em;
-    font-family: monospace;
-}
-
-.viewcode-back {
-    font-family: Arial, sans-serif;
-}
-
-div.viewcode-block:target {
-    background-color: #f4debf;
-    border-top: 1px solid #ac9;
-    border-bottom: 1px solid #ac9;
-}
-
-p {
-	margin: 0;
-}
-
-ul li dd {
-	margin-top: 0;
-}
-
-ul li dl {
-	margin-bottom: 0;
-}
-
-li dl dd {
-	margin-bottom: 0;
-}
-
-dd ul {
-	padding-left: 0;
-}
-
-li dd ul {
-	margin-bottom: 0;
-}
-
diff --git a/synapse/api/events/factory.py b/synapse/api/events/factory.py
index 0d94850cecb8f3c926093b43fded3775a0764ebb..74d0ef77f4b78d720cab6c29f822621056f790b0 100644
--- a/synapse/api/events/factory.py
+++ b/synapse/api/events/factory.py
@@ -58,8 +58,8 @@ class EventFactory(object):
                 random_string(10), self.hs.hostname
             )
 
-        if "ts" not in kwargs:
-            kwargs["ts"] = int(self.clock.time_msec())
+        if "origin_server_ts" not in kwargs:
+            kwargs["origin_server_ts"] = int(self.clock.time_msec())
 
         # The "age" key is a delta timestamp that should be converted into an
         # absolute timestamp the minute we see it.
diff --git a/synapse/federation/pdu_codec.py b/synapse/federation/pdu_codec.py
index 7e574f451ddad2cfed38f9abb358a9388f7b4586..991aae2a5693c824b8cf6efb55a8ec0fe8e4a57a 100644
--- a/synapse/federation/pdu_codec.py
+++ b/synapse/federation/pdu_codec.py
@@ -95,8 +95,8 @@ class PduCodec(object):
             if k not in ["event_id", "room_id", "type"]
         })
 
-        if "ts" not in kwargs:
-            kwargs["ts"] = int(self.clock.time_msec())
+        if "origin_server_ts" not in kwargs:
+            kwargs["origin_server_ts"] = int(self.clock.time_msec())
 
         pdu = Pdu(**kwargs)
         pdu = add_event_pdu_content_hash(pdu)
diff --git a/synapse/federation/persistence.py b/synapse/federation/persistence.py
index de36a80e41d4c43c3bfc69706785f8183cf2ad8c..7043fcc504cc35db91b0e87320b01ef52775c3bf 100644
--- a/synapse/federation/persistence.py
+++ b/synapse/federation/persistence.py
@@ -157,7 +157,7 @@ class TransactionActions(object):
         transaction.prev_ids = yield self.store.prep_send_transaction(
             transaction.transaction_id,
             transaction.destination,
-            transaction.ts,
+            transaction.origin_server_ts,
             [(p["pdu_id"], p["origin"]) for p in transaction.pdus]
         )
 
diff --git a/synapse/federation/replication.py b/synapse/federation/replication.py
index f2a5d4d5e2375f5b71ef0444e59149b2f5b7659d..4a9414c1d4e6e264c7a1f7790c8229058e29aaeb 100644
--- a/synapse/federation/replication.py
+++ b/synapse/federation/replication.py
@@ -427,7 +427,7 @@ class ReplicationLayer(object):
         return Transaction(
             origin=self.server_name,
             pdus=pdus,
-            ts=int(time_now),
+            origin_server_ts=int(time_now),
             destination=None,
         )
 
@@ -595,7 +595,7 @@ class _TransactionQueue(object):
             logger.debug("TX [%s] Persisting transaction...", destination)
 
             transaction = Transaction.create_new(
-                ts=int(self._clock.time_msec()),
+                origin_server_ts=int(self._clock.time_msec()),
                 transaction_id=str(self._next_txn_id),
                 origin=self.server_name,
                 destination=destination,
diff --git a/synapse/federation/units.py b/synapse/federation/units.py
index c629e5793ebefed30051b5c13fec804a95f2f450..b81e1625124cceb433d8dfa342523871ea1677d4 100644
--- a/synapse/federation/units.py
+++ b/synapse/federation/units.py
@@ -41,7 +41,7 @@ class Pdu(JsonEncodedObject):
 
         {
             "pdu_id": "78c",
-            "ts": 1404835423000,
+            "origin_server_ts": 1404835423000,
             "origin": "bar",
             "prev_ids": [
                 ["23b", "foo"],
@@ -56,7 +56,7 @@ class Pdu(JsonEncodedObject):
         "pdu_id",
         "context",
         "origin",
-        "ts",
+        "origin_server_ts",
         "pdu_type",
         "destinations",
         "transaction_id",
@@ -84,7 +84,7 @@ class Pdu(JsonEncodedObject):
         "pdu_id",
         "context",
         "origin",
-        "ts",
+        "origin_server_ts",
         "pdu_type",
         "content",
     ]
@@ -122,6 +122,7 @@ class Pdu(JsonEncodedObject):
         """
         if pdu_tuple:
             d = copy.copy(pdu_tuple.pdu_entry._asdict())
+            d["origin_server_ts"] = d.pop("ts")
 
             for k in d.keys():
                 if d[k] is None:
@@ -212,7 +213,7 @@ class Transaction(JsonEncodedObject):
         "transaction_id",
         "origin",
         "destination",
-        "ts",
+        "origin_server_ts",
         "previous_ids",
         "pdus",
         "edus",
@@ -229,7 +230,7 @@ class Transaction(JsonEncodedObject):
         "transaction_id",
         "origin",
         "destination",
-        "ts",
+        "origin_server_ts",
         "pdus",
     ]
 
@@ -251,10 +252,10 @@ class Transaction(JsonEncodedObject):
     @staticmethod
     def create_new(pdus, **kwargs):
         """ Used to create a new transaction. Will auto fill out
-        transaction_id and ts keys.
+        transaction_id and origin_server_ts keys.
         """
-        if "ts" not in kwargs:
-            raise KeyError("Require 'ts' to construct a Transaction")
+        if "origin_server_ts" not in kwargs:
+            raise KeyError("Require 'origin_server_ts' to construct a Transaction")
         if "transaction_id" not in kwargs:
             raise KeyError(
                 "Require 'transaction_id' to construct a Transaction"
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 317ef2c80ce9449c002f88308f2a12eaff323f1e..7b2b8549edc1d1e8ed890c46759e940653b5783a 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -64,7 +64,7 @@ class MessageHandler(BaseHandler):
         defer.returnValue(None)
 
     @defer.inlineCallbacks
-    def send_message(self, event=None, suppress_auth=False, stamp_event=True):
+    def send_message(self, event=None, suppress_auth=False):
         """ Send a message.
 
         Args:
@@ -72,7 +72,6 @@ class MessageHandler(BaseHandler):
             suppress_auth (bool) : True to suppress auth for this message. This
             is primarily so the home server can inject messages into rooms at
             will.
-            stamp_event (bool) : True to stamp event content with server keys.
         Raises:
             SynapseError if something went wrong.
         """
@@ -82,9 +81,6 @@ class MessageHandler(BaseHandler):
         user = self.hs.parse_userid(event.user_id)
         assert user.is_mine, "User must be our own: %s" % (user,)
 
-        if stamp_event:
-            event.content["hsob_ts"] = int(self.clock.time_msec())
-
         snapshot = yield self.store.snapshot_room(event.room_id, event.user_id)
 
         if not suppress_auth:
@@ -132,7 +128,7 @@ class MessageHandler(BaseHandler):
         defer.returnValue(chunk)
 
     @defer.inlineCallbacks
-    def store_room_data(self, event=None, stamp_event=True):
+    def store_room_data(self, event=None):
         """ Stores data for a room.
 
         Args:
@@ -151,9 +147,6 @@ class MessageHandler(BaseHandler):
 
         yield self.auth.check(event, snapshot, raises=True)
 
-        if stamp_event:
-            event.content["hsob_ts"] = int(self.clock.time_msec())
-
         yield self.state_handler.handle_new_event(event, snapshot)
 
         yield self._on_new_room_event(event, snapshot)
@@ -221,10 +214,7 @@ class MessageHandler(BaseHandler):
         defer.returnValue(None)
 
     @defer.inlineCallbacks
-    def send_feedback(self, event, stamp_event=True):
-        if stamp_event:
-            event.content["hsob_ts"] = int(self.clock.time_msec())
-
+    def send_feedback(self, event):
         snapshot = yield self.store.snapshot_room(event.room_id, event.user_id)
 
         yield self.auth.check(event, snapshot, raises=True)
diff --git a/synapse/rest/presence.py b/synapse/rest/presence.py
index 7fc8ce44045918d58da4f37dbe028eea13171c2c..138cc88a055880a8669c8abf2f37a0638dd5b656 100644
--- a/synapse/rest/presence.py
+++ b/synapse/rest/presence.py
@@ -68,7 +68,7 @@ class PresenceStatusRestServlet(RestServlet):
         yield self.handlers.presence_handler.set_state(
             target_user=user, auth_user=auth_user, state=state)
 
-        defer.returnValue((200, ""))
+        defer.returnValue((200, {}))
 
     def on_OPTIONS(self, request):
         return (200, {})
@@ -141,7 +141,7 @@ class PresenceListRestServlet(RestServlet):
 
         yield defer.DeferredList(deferreds)
 
-        defer.returnValue((200, ""))
+        defer.returnValue((200, {}))
 
     def on_OPTIONS(self, request):
         return (200, {})
diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py
index 1738260cc12d27f0bafa7488bbb316412ff20128..e4f708b6ad070e7965e1d343f8992fc023faa231 100644
--- a/synapse/storage/__init__.py
+++ b/synapse/storage/__init__.py
@@ -163,6 +163,8 @@ class DataStore(RoomMemberStore, RoomStore,
 
         cols["unrecognized_keys"] = json.dumps(unrec_keys)
 
+        cols["ts"] = cols.pop("origin_server_ts")
+
         logger.debug("Persisting: %s", repr(cols))
 
         for hash_alg, hash_base64 in pdu.hashes.items():
diff --git a/synapse/storage/_base.py b/synapse/storage/_base.py
index dba50f1213133bab1371ab71f734591da4d62828..65a86e905660ae4e0acb4dcc9fbff02c21ec025d 100644
--- a/synapse/storage/_base.py
+++ b/synapse/storage/_base.py
@@ -354,6 +354,7 @@ class SQLBaseStore(object):
         d.pop("stream_ordering", None)
         d.pop("topological_ordering", None)
         d.pop("processed", None)
+        d["origin_server_ts"] = d.pop("ts", 0)
 
         d.update(json.loads(row_dict["unrecognized_keys"]))
         d["content"] = json.loads(d["content"])
@@ -361,7 +362,7 @@ class SQLBaseStore(object):
 
         if "age_ts" not in d:
             # For compatibility
-            d["age_ts"] = d["ts"] if "ts" in d else 0
+            d["age_ts"] = d.get("origin_server_ts", 0)
 
         return self.event_factory.create_event(
             etype=d["type"],
diff --git a/synapse/storage/transactions.py b/synapse/storage/transactions.py
index ab4599b468336c1b597128ef3e4a957d64f76cc8..2ba8e30efe1ffca9b045a87f7dcb8eb2d99b8943 100644
--- a/synapse/storage/transactions.py
+++ b/synapse/storage/transactions.py
@@ -87,7 +87,8 @@ class TransactionStore(SQLBaseStore):
 
         txn.execute(query, (code, response_json, transaction_id, origin))
 
-    def prep_send_transaction(self, transaction_id, destination, ts, pdu_list):
+    def prep_send_transaction(self, transaction_id, destination,
+                              origin_server_ts, pdu_list):
         """Persists an outgoing transaction and calculates the values for the
         previous transaction id list.
 
@@ -97,7 +98,7 @@ class TransactionStore(SQLBaseStore):
         Args:
             transaction_id (str)
             destination (str)
-            ts (int)
+            origin_server_ts (int)
             pdu_list (list)
 
         Returns:
@@ -106,11 +107,11 @@ class TransactionStore(SQLBaseStore):
 
         return self.runInteraction(
             self._prep_send_transaction,
-            transaction_id, destination, ts, pdu_list
+            transaction_id, destination, origin_server_ts, pdu_list
         )
 
-    def _prep_send_transaction(self, txn, transaction_id, destination, ts,
-                               pdu_list):
+    def _prep_send_transaction(self, txn, transaction_id, destination,
+                               origin_server_ts, pdu_list):
 
         # First we find out what the prev_txs should be.
         # Since we know that we are only sending one transaction at a time,
@@ -131,7 +132,7 @@ class TransactionStore(SQLBaseStore):
             None,
             transaction_id=transaction_id,
             destination=destination,
-            ts=ts,
+            ts=origin_server_ts,
             response_code=0,
             response_json=None
         ))
diff --git a/tests/federation/test_federation.py b/tests/federation/test_federation.py
index eed50e6335180abc7c39b5c81ee51aa8edebd898..3a14c7c3b95d23d9fa5e8c28e256cb373fbfabe7 100644
--- a/tests/federation/test_federation.py
+++ b/tests/federation/test_federation.py
@@ -158,7 +158,7 @@ class FederationTestCase(unittest.TestCase):
                 origin="red",
                 destinations=["remote"],
                 context="my-context",
-                ts=123456789002,
+                origin_server_ts=123456789002,
                 pdu_type="m.test",
                 content={"testing": "content here"},
                 depth=1,
@@ -170,14 +170,14 @@ class FederationTestCase(unittest.TestCase):
                 "remote",
                 path="/_matrix/federation/v1/send/1000000/",
                 data={
-                    "ts": 1000000,
+                    "origin_server_ts": 1000000,
                     "origin": "test",
                     "pdus": [
                         {
                             "origin": "red",
                             "pdu_id": "abc123def456",
                             "prev_pdus": [],
-                            "ts": 123456789002,
+                            "origin_server_ts": 123456789002,
                             "context": "my-context",
                             "pdu_type": "m.test",
                             "is_state": False,
@@ -209,7 +209,7 @@ class FederationTestCase(unittest.TestCase):
                 path="/_matrix/federation/v1/send/1000000/",
                 data={
                     "origin": "test",
-                    "ts": 1000000,
+                    "origin_server_ts": 1000000,
                     "pdus": [],
                     "edus": [
                         {
@@ -236,7 +236,7 @@ class FederationTestCase(unittest.TestCase):
                 "/_matrix/federation/v1/send/1001000/",
                 """{
                     "origin": "remote",
-                    "ts": 1001000,
+                    "origin_server_ts": 1001000,
                     "pdus": [],
                     "edus": [
                         {
diff --git a/tests/federation/test_pdu_codec.py b/tests/federation/test_pdu_codec.py
index 0ad8cf6641098857e8fd91c6fadc72c060866ed0..fd0f72c734e324f12a248f6c731629472f0e72dc 100644
--- a/tests/federation/test_pdu_codec.py
+++ b/tests/federation/test_pdu_codec.py
@@ -75,7 +75,7 @@ class PduCodecTestCase(unittest.TestCase):
             context="rooooom",
             pdu_type="m.room.message",
             origin="bar.com",
-            ts=12345,
+            origin_server_ts=12345,
             depth=5,
             prev_pdus=[("alice", "bob.com")],
             is_state=False,
@@ -130,7 +130,7 @@ class PduCodecTestCase(unittest.TestCase):
             context="rooooom",
             pdu_type="m.room.topic",
             origin="bar.com",
-            ts=12345,
+            origin_server_ts=12345,
             depth=5,
             prev_pdus=[("alice", "bob.com")],
             is_state=True,
diff --git a/tests/handlers/test_federation.py b/tests/handlers/test_federation.py
index 35c3a4df7bbb46c84e3426147b25e2824d036ddb..219b2c4c5ee179d6728417885426b7ff8c8c0106 100644
--- a/tests/handlers/test_federation.py
+++ b/tests/handlers/test_federation.py
@@ -68,7 +68,7 @@ class FederationTestCase(unittest.TestCase):
             pdu_type=MessageEvent.TYPE,
             context="foo",
             content={"msgtype": u"fooo"},
-            ts=0,
+            origin_server_ts=0,
             pdu_id="a",
             origin="b",
         )
@@ -95,7 +95,7 @@ class FederationTestCase(unittest.TestCase):
             target_host=self.hostname,
             context=room_id,
             content={},
-            ts=0,
+            origin_server_ts=0,
             pdu_id="a",
             origin="b",
         )
@@ -127,7 +127,7 @@ class FederationTestCase(unittest.TestCase):
             state_key="@red:not%s" % self.hostname,
             context=room_id,
             content={},
-            ts=0,
+            origin_server_ts=0,
             pdu_id="a",
             origin="b",
         )
diff --git a/tests/handlers/test_presence.py b/tests/handlers/test_presence.py
index 84985a806676cdba6db3d971423e8f5d4d44754d..1850deacf5edf4ae7674e893097219179c76f094 100644
--- a/tests/handlers/test_presence.py
+++ b/tests/handlers/test_presence.py
@@ -39,7 +39,7 @@ ONLINE = PresenceState.ONLINE
 def _expect_edu(destination, edu_type, content, origin="test"):
     return {
         "origin": origin,
-        "ts": 1000000,
+        "origin_server_ts": 1000000,
         "pdus": [],
         "edus": [
             {
diff --git a/tests/handlers/test_typing.py b/tests/handlers/test_typing.py
index b685373deb1fba1fd6f3f812445f742747c58f88..f1d3b27f741bfc0874230653c4de4ff40cfe41c9 100644
--- a/tests/handlers/test_typing.py
+++ b/tests/handlers/test_typing.py
@@ -29,7 +29,7 @@ from synapse.handlers.typing import TypingNotificationHandler
 def _expect_edu(destination, edu_type, content, origin="test"):
     return {
         "origin": origin,
-        "ts": 1000000,
+        "origin_server_ts": 1000000,
         "pdus": [],
         "edus": [
             {
diff --git a/tests/test_state.py b/tests/test_state.py
index b1624f0b259df3a1e28b8e8b084484ff31548ff1..4b1feaf4106e7c780481745ff6cd7eedfa981170 100644
--- a/tests/test_state.py
+++ b/tests/test_state.py
@@ -599,7 +599,7 @@ def new_fake_pdu(pdu_id, context, pdu_type, state_key, prev_state_id,
         prev_state_id=prev_state_id,
         origin="example.com",
         context="context",
-        ts=1405353060021,
+        origin_server_ts=1405353060021,
         depth=depth,
         content_json="{}",
         unrecognized_keys="{}",
diff --git a/webclient/app-filter.js b/webclient/app-filter.js
index fc16492ef31f96cb495aae2d02d8bc1c32fb5cfc..39ea1d637d852447c9e77fa7afcec9c6f6a32034 100644
--- a/webclient/app-filter.js
+++ b/webclient/app-filter.js
@@ -1,12 +1,12 @@
 /*
  Copyright 2014 OpenMarket Ltd
- 
+
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
- 
+
  http://www.apache.org/licenses/LICENSE-2.0
- 
+
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -80,4 +80,53 @@ angular.module('matrixWebClient')
     return function(text) {
         return $sce.trustAsHtml(text);
     };
-}]);
\ No newline at end of file
+}])
+// Exactly the same as ngSanitize's linky but instead of pushing sanitized
+// text in the addText function, we just push the raw text.
+.filter('unsanitizedLinky', ['$sanitize', function($sanitize) {
+  var LINKY_URL_REGEXP =
+        /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
+      MAILTO_REGEXP = /^mailto:/;
+
+  return function(text, target) {
+    if (!text) return text;
+    var match;
+    var raw = text;
+    var html = [];
+    var url;
+    var i;
+    while ((match = raw.match(LINKY_URL_REGEXP))) {
+      // We can not end in these as they are sometimes found at the end of the sentence
+      url = match[0];
+      // if we did not match ftp/http/mailto then assume mailto
+      if (match[2] == match[3]) url = 'mailto:' + url;
+      i = match.index;
+      addText(raw.substr(0, i));
+      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
+      raw = raw.substring(i + match[0].length);
+    }
+    addText(raw);
+    return $sanitize(html.join(''));
+
+    function addText(text) {
+      if (!text) {
+        return;
+      }
+      html.push(text);
+    }
+
+    function addLink(url, text) {
+      html.push('<a ');
+      if (angular.isDefined(target)) {
+        html.push('target="');
+        html.push(target);
+        html.push('" ');
+      }
+      html.push('href="');
+      html.push(url);
+      html.push('">');
+      addText(text);
+      html.push('</a>');
+    }
+  };
+}]);
diff --git a/webclient/room/room.html b/webclient/room/room.html
index b99413cbbf66ed41f68ffef9d002d28a6c0588b8..79a60585a581d1e38c9c0ecab9340ed35dd9fe87 100644
--- a/webclient/room/room.html
+++ b/webclient/room/room.html
@@ -121,7 +121,9 @@
                         <span ng-show='msg.content.msgtype === "m.text"' 
                               class="message"
                               ng-class="containsBingWord(msg.content.body) && msg.user_id != state.user_id ? msg.echo_msg_state + ' messageBing' : msg.echo_msg_state"
-                              ng-bind-html="((msg.content.msgtype === 'm.text') ? msg.content.body : '') | linky:'_blank'"/>
+                              ng-bind-html="(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message' && msg.content.format === 'org.matrix.custom.html') ? 
+                                                                                        (msg.content.formatted_body | unsanitizedLinky) :
+                                             (msg.content.msgtype === 'm.text' && msg.type === 'm.room.message') ? (msg.content.body | linky:'_blank') : '' "/>
 
                         <span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id'>Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span>
                         <span ng-show='msg.type === "m.call.invite" && msg.user_id != state.user_id'>Incoming Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span>