diff --git a/PKG-INFO b/PKG-INFO
index f9bcafd17410f37d9819e23c4137799b7c4f14f0..6bc733ad5b95c2e35c582409a392cab46405d246 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,14 +1,14 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 0.0.41
+Version: 0.0.42
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
 Author-email: swh-devel@inria.fr
 License: UNKNOWN
 Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
-Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Project-URL: Funding, https://www.softwareheritage.org/donate
+Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Description: swh-model
         =========
         
diff --git a/swh.model.egg-info/PKG-INFO b/swh.model.egg-info/PKG-INFO
index f9bcafd17410f37d9819e23c4137799b7c4f14f0..6bc733ad5b95c2e35c582409a392cab46405d246 100644
--- a/swh.model.egg-info/PKG-INFO
+++ b/swh.model.egg-info/PKG-INFO
@@ -1,14 +1,14 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 0.0.41
+Version: 0.0.42
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
 Author-email: swh-devel@inria.fr
 License: UNKNOWN
 Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
-Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Project-URL: Funding, https://www.softwareheritage.org/donate
+Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Description: swh-model
         =========
         
diff --git a/swh/model/hypothesis_strategies.py b/swh/model/hypothesis_strategies.py
index e20f4ea114d097f0d728b3c672cabe698d3e219f..3a205a3ca779def557ab2eb11b8d615b8e9d2c8e 100644
--- a/swh/model/hypothesis_strategies.py
+++ b/swh/model/hypothesis_strategies.py
@@ -78,7 +78,9 @@ def origin_visits():
     return builds(
         OriginVisit,
         visit=integers(0, 1000),
-        origin=origins())
+        origin=origins(),
+        status=sampled_from(['ongoing', 'full', 'partial']),
+        type=pgsql_text())
 
 
 @composite
@@ -178,7 +180,10 @@ def branch_targets(*, only_objects=False):
 def snapshots(draw, *, min_size=0, max_size=100, only_objects=False):
     branches = draw(dictionaries(
         keys=branch_names(),
-        values=branch_targets(only_objects=only_objects),
+        values=one_of(
+            none(),
+            branch_targets(only_objects=only_objects)
+        ),
         min_size=min_size,
         max_size=max_size,
     ))
@@ -200,7 +205,7 @@ def snapshots(draw, *, min_size=0, max_size=100, only_objects=False):
         try:
             id_ = snapshot_identifier({
                 'branches': {
-                    name: branch.to_dict()
+                    name: branch.to_dict() if branch else None
                     for (name, branch) in branches.items()}})
         except ValueError as e:
             for (source, target) in e.args[1]:
diff --git a/swh/model/model.py b/swh/model/model.py
index 36f8ef3f1838fcf0ea8c632962cde906ee7db5bb..3ee19a83a89e5af67ef7a5a030abc76343ede1ee 100644
--- a/swh/model/model.py
+++ b/swh/model/model.py
@@ -104,15 +104,22 @@ class OriginVisit(BaseModel):
     SWH loader."""
     origin = attr.ib(type=Origin)
     date = attr.ib(type=datetime.datetime)
+    status = attr.ib(
+        type=str,
+        validator=attr.validators.in_(['ongoing', 'full', 'partial']))
+    type = attr.ib(type=str)
+    snapshot = attr.ib(type=Sha1Git)
+    metadata = attr.ib(type=Optional[Dict[str, object]],
+                       default=None)
+
     visit = attr.ib(type=Optional[int],
-                    validator=attr.validators.optional([]))
+                    default=None)
     """Should not be set before calling 'origin_visit_add()'."""
 
     def to_dict(self):
         """Serializes the date as a string and omits the visit id if it is
         `None`."""
         ov = super().to_dict()
-        ov['date'] = str(self.date)
         if ov['visit'] is None:
             del ov['visit']
         return ov
@@ -120,10 +127,14 @@ class OriginVisit(BaseModel):
     @classmethod
     def from_dict(cls, d):
         """Parses the date from a string, and accepts missing visit ids."""
+        d = d.copy()
+        date = d.pop('date')
         return cls(
-            origin=Origin.from_dict(d['origin']),
-            date=dateutil.parser.parse(d['date']),
-            visit=d.get('visit'))
+            origin=Origin.from_dict(d.pop('origin')),
+            date=(date
+                  if isinstance(date, datetime.datetime)
+                  else dateutil.parser.parse(date)),
+            **d)
 
 
 class TargetType(Enum):
@@ -183,7 +194,7 @@ class Snapshot(BaseModel):
         return {
             'id': self.id,
             'branches': {
-                name: branch.to_dict()
+                name: branch.to_dict() if branch else None
                 for (name, branch) in self.branches.items()
             }
         }
@@ -193,7 +204,7 @@ class Snapshot(BaseModel):
         return cls(
             id=d['id'],
             branches={
-                name: SnapshotBranch.from_dict(branch)
+                name: SnapshotBranch.from_dict(branch) if branch else None
                 for (name, branch) in d['branches'].items()
             })
 
@@ -227,6 +238,8 @@ class Release(BaseModel):
         rel = attr.asdict(self)
         rel['date'] = self.date.to_dict() if self.date is not None else None
         rel['target_type'] = rel['target_type'].value
+        if rel['metadata'] is None:
+            del rel['metadata']
         return rel
 
     @classmethod
diff --git a/swh/model/tests/test_hypothesis_strategies.py b/swh/model/tests/test_hypothesis_strategies.py
index 09c21d8119359c4d3849dc23d8dcb10bb3de1bc8..2182064c3dbbf1745258b867762758c89ea20a65 100644
--- a/swh/model/tests/test_hypothesis_strategies.py
+++ b/swh/model/tests/test_hypothesis_strategies.py
@@ -3,6 +3,8 @@
 # License: GNU General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
+import datetime
+
 import attr
 from hypothesis import given
 
@@ -30,7 +32,8 @@ def assert_nested_dict(obj):
     elif isinstance(obj, list):
         for value in obj:
             assert_nested_dict(value)
-    elif isinstance(obj, (int, float, str, bytes, bool, type(None))):
+    elif isinstance(obj, (int, float, str, bytes, bool, type(None),
+                          datetime.datetime)):
         pass
     else:
         assert False, obj
@@ -56,4 +59,4 @@ def test_dicts_generation(obj_type_and_obj):
         assert object_['target_type'] in target_types
     elif obj_type == 'snapshot':
         for branch in object_['branches'].values():
-            assert branch['target_type'] in target_types
+            assert branch is None or branch['target_type'] in target_types
diff --git a/version.txt b/version.txt
index d73351960bdbc86edfc8ef92e7024fa8f81763ad..29db2c20c626155010e014246ba22dd264740ee4 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-v0.0.41-0-g01a5d4c
\ No newline at end of file
+v0.0.42-0-g6df68b0
\ No newline at end of file