diff --git a/orgmode-parse.cabal b/orgmode-parse.cabal
--- a/orgmode-parse.cabal
+++ b/orgmode-parse.cabal
@@ -1,5 +1,5 @@
 Name:                   orgmode-parse
-Version:                0.0.2.1
+Version:                0.1.0
 Author:                 Parnell Springmeyer <parnell@digitalmentat.com>
 Maintainer:             Parnell Springmeyer <parnell@digitalmentat.com>
 License:                BSD3
@@ -37,13 +37,17 @@
     Data.OrgMode.Parse.Types
 
   Build-Depends:
-    base                      >= 4.4      && < 5,
-    attoparsec                >= 0.12     && < 0.13,
-    unordered-containers      >= 0.2      && < 0.3,
-    thyme                     >= 0.3      && < 0.4,
-    old-locale                >= 1.0      && < 2.0,
-    free                      >= 4.9      && < 5,
-    text                      >= 1.0      && < 2.0
+                  aeson                     >= 0.8.0.2  && < 0.9
+                , attoparsec                >= 0.12     && < 0.13
+                , base                      >= 4.4      && < 5
+                , bytestring                >= 0.10.4   && < 0.11
+                , containers                >= 0.5.5    && < 0.6
+                , free                      >= 4.9      && < 5
+                , hashable                  >= 1.2      && < 1.3
+                , old-locale                >= 1.0      && < 2.0
+                , text                      >= 1.0      && < 2.0
+                , thyme                     >= 0.3      && < 0.4
+                , unordered-containers      >= 0.2      && < 0.3
 
 Test-Suite tests
   Type:                 exitcode-stdio-1.0
@@ -56,14 +60,18 @@
 
   Build-Depends:
     base                       >= 4.4      && < 5,
+    aeson                      >= 0.8      && < 0.9,
+    bytestring                 >= 0.10     && < 0.11,
     text                       >= 1.0      && < 2.0,
     attoparsec                 >= 0.12     && < 0.13,
+    hashable                   >= 1.2      && < 1.3,
     unordered-containers       >= 0.2      && < 0.3,
     thyme                      >= 0.3      && < 0.4,
     old-locale                 >= 1.0      && < 2.0,
     HUnit                      >= 1.2.5.2  && < 1.3,
-    tasty                      >= 0.8      && < 0.9,
-    tasty-hunit                >= 0.8.0.1  && < 0.9
+    tasty                      >= 0.8      && < 0.11,
+    tasty-hunit                >= 0.8.0.1  && < 0.9,
+    containers
 
 Source-Repository head
   Type:                 git
diff --git a/src/Data/OrgMode/Parse.hs b/src/Data/OrgMode/Parse.hs
--- a/src/Data/OrgMode/Parse.hs
+++ b/src/Data/OrgMode/Parse.hs
@@ -1,26 +1,42 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Data.OrgMode.Parse.Attoparsec.Headings
--- Copyright   :  © 2014 Parnell Springmeyer
--- License     :  All Rights Reserved
--- Maintainer  :  Parnell Springmeyer <parnell@digitalmentat.com>
--- Stability   :  stable
---
--- Attoparsec combinators for orgmode documents.
-----------------------------------------------------------------------------
+{-|
+Module      :  Data.OrgMode.Parse.Attoparsec.Headings
+Copyright   :  © 2014 Parnell Springmeyer
+License     :  All Rights Reserved
+Maintainer  :  Parnell Springmeyer <parnell@digitalmentat.com>
+Stability   :  stable
 
-module Data.OrgMode.Parse
-(
--- * Parse Document
+Attoparsec combinators for orgmode documents.
+-}
 
--- * Parse Headline
-  module Data.OrgMode.Parse.Attoparsec.Headings
--- * Parse Headline Metadata (properties, timestamps, etc...)
-, module Data.OrgMode.Parse.Attoparsec.Time
+module Data.OrgMode.Parse (
+
+-- * Parse OrgMode documents
+  module Data.OrgMode.Parse.Attoparsec.Document
+
+-- * OrgMode Document structure
+, module Data.OrgMode.Parse.Types
+
+-- * Parse headlines
+, module Data.OrgMode.Parse.Attoparsec.Headings
+
+-- * Parse headline metadata sections
+, module Data.OrgMode.Parse.Attoparsec.Section
+
+-- * Parse metadata property drawers
 , module Data.OrgMode.Parse.Attoparsec.PropertyDrawer
--- * Parse Body
+
+-- * Parse metadata timestamps and modifiers
+, module Data.OrgMode.Parse.Attoparsec.Time
 ) where
 
-import           Data.OrgMode.Parse.Attoparsec.Headings
-import           Data.OrgMode.Parse.Attoparsec.PropertyDrawer
-import           Data.OrgMode.Parse.Attoparsec.Time
+import Data.OrgMode.Parse.Attoparsec.Document
+
+import Data.OrgMode.Parse.Attoparsec.Section
+
+import Data.OrgMode.Parse.Attoparsec.Headings
+
+import Data.OrgMode.Parse.Attoparsec.PropertyDrawer
+
+import Data.OrgMode.Parse.Attoparsec.Time
+
+import Data.OrgMode.Parse.Types
diff --git a/src/Data/OrgMode/Parse/Types.hs b/src/Data/OrgMode/Parse/Types.hs
--- a/src/Data/OrgMode/Parse/Types.hs
+++ b/src/Data/OrgMode/Parse/Types.hs
@@ -1,77 +1,220 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Data.OrgMode.Parse.Types
--- Copyright   :  © 2014 Parnell Springmeyer
--- License     :  All Rights Reserved
--- Maintainer  :  Parnell Springmeyer <parnell@digitalmentat.com>
--- Stability   :  stable
---
--- Types and utility functions.
-----------------------------------------------------------------------------
+{-|
+Module      :  Data.OrgMode.Parse.Types
+Copyright   :  © 2014 Parnell Springmeyer
+License     :  All Rights Reserved
+Maintainer  :  Parnell Springmeyer <parnell@digitalmentat.com>
+Stability   :  experimental
 
+Types and utility functions.
+-}
+
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DeriveGeneric     #-}
 
 module Data.OrgMode.Parse.Types
-( Heading  (..)
+( Document (..)
+, Section (..)
+, Heading  (..)
 , Priority (..)
-, State    (..)
-, Keyword  (..)
-, PropertyDrawer (..)
-, Schedule     (..)
-, ScheduleType (..)
+, Plannings (..)
+, StateKeyword  (..)
+, Duration
+, PlanningKeyword (..)
+, Properties
 , Timestamp    (..)
-, Open         (..)
-, Close        (..)
-, toPriority
+, DateTime (..)
+, Stats (..)
+, Tag
+, TimeUnit (..)
+, RepeaterType (..)
+, Repeater (..)
+, DelayType (..)
+, Delay (..)
+, YearMonthDay(..)
+, YearMonthDay'(..)
 ) where
 
-import           Data.HashMap.Strict  (HashMap)
-import           Data.Text            (Text)
-import           Data.Thyme.LocalTime (LocalTime (..))
+import           Control.Applicative
+import           Control.Monad        (mzero)
+import qualified Data.Aeson           as A
+import           Data.Aeson           ((.=),(.:))
+import           Data.Hashable        (Hashable(..))
+import           Data.HashMap.Strict  (HashMap, fromList, toList, keys)
+import           Data.Text            (Text, pack)
+import           Data.Thyme.Calendar  (YearMonthDay(..))
+import           Data.Thyme.LocalTime (Hour, Minute)
+import           Data.Traversable
+import           GHC.Generics
 
-----------------------------------------------------------------------------
+data Document = Document {
+    documentText     :: Text      -- ^ Text occurring before any Org headlines
+  , documentHeadings :: [Heading] -- ^ Toplevel Org headlines
+  } deriving (Show, Eq, Generic)
 
+instance A.ToJSON Document where
+instance A.FromJSON Document where
+
 data Heading = Heading
-    { level    :: Int
-    , priority :: Maybe Priority
-    , state    :: Maybe State
-    , title    :: Text
-    , keywords :: [Keyword]
-    } deriving (Show, Eq)
+    { level       :: Int                -- ^ Org headline nesting level (1 is at the top)
+    , keyword     :: Maybe StateKeyword -- ^ State of the headline (e.g. TODO, DONE)
+    , priority    :: Maybe Priority     --
+    , title       :: Text               -- properties
+    , stats       :: Maybe Stats        --
+    , tags        :: [Tag]             --
+    , section     :: Section            -- Next-line
+    , subHeadings :: [Heading]          -- elements
+    } deriving (Show, Eq, Generic)
 
+type Properties = HashMap Text Text
+type Clock      = (Maybe Timestamp, Maybe Duration)
 
-data Priority = A | B | C | Unknown
-  deriving (Show, Read, Eq, Ord)
+data Section = Section {
+      sectionPlannings  :: Plannings
+    , sectionClocks     :: [Clock]
+    , sectionProperties :: Properties
+    , sectionParagraph  :: Text
+  } deriving (Show, Eq, Generic)
 
-newtype State = State Text
-  deriving (Show, Eq)
 
-newtype Keyword = Keyword Text
-  deriving (Show, Eq, Ord)
+data Timestamp = Timestamp {
+    tsTime    :: DateTime
+  , tsActive  :: Bool
+  , tsEndTime :: Maybe DateTime
+  } deriving (Show, Eq, Generic)
 
-toPriority :: Text -> Priority
-toPriority "A" = A
-toPriority "B" = B
-toPriority "C" = C
-toPriority _   = Unknown
+instance A.ToJSON Timestamp where
+instance A.FromJSON Timestamp where
 
-----------------------------------------------------------------------------
 
-newtype PropertyDrawer k v = PropertyDrawer (HashMap k v)
-  deriving (Show, Eq)
+newtype YearMonthDay' = YMD' YearMonthDay
+                        deriving (Show, Eq, Generic)
 
-----------------------------------------------------------------------------
-data Schedule = Schedule
-    { schedule_type :: ScheduleType
-    , timestamp     :: Maybe Timestamp
-    , recurring     :: Maybe Text
-    } deriving (Show, Eq)
+instance A.ToJSON YearMonthDay' where
+  toJSON (YMD' (YearMonthDay y m d)) =
+    A.object ["ymdYear"  .= y
+             ,"ymdMonth" .= m
+             ,"ymdDay"   .= d]
 
-data ScheduleType = SCHEDULED | DEADLINE | APPOINTMENT
-  deriving (Show, Eq)
+instance A.FromJSON YearMonthDay' where
+  parseJSON (A.Object v) = do
+    y <- v .: "ymdYear"
+    m <- v .: "ymdMonth"
+    d <- v .: "ymdDay"
+    return (YMD' (YearMonthDay y m d))
+  parseJSON _ = mzero
 
-data Timestamp = Active LocalTime | Inactive LocalTime
-  deriving (Show, Eq)
+data DateTime = DateTime {
+    yearMonthDay :: YearMonthDay'
+  , dayName      :: Maybe Text
+  , hourMinute   :: Maybe (Hour,Minute)
+  , repeater     :: Maybe Repeater
+  , delay        :: Maybe Delay
+  } deriving (Show, Eq, Generic)
 
-newtype Open = Open Char
-newtype Close = Close Char
+instance A.ToJSON DateTime where
+instance A.FromJSON DateTime where
+
+data RepeaterType = RepeatCumulate | RepeatCatchUp | RepeatRestart
+                  deriving (Show, Eq, Generic)
+
+instance A.ToJSON RepeaterType
+instance A.FromJSON RepeaterType
+
+data Repeater = Repeater {
+    repeaterType  :: RepeaterType
+  , repeaterValue :: Int
+  , repeaterUnit  :: TimeUnit
+  } deriving (Show, Eq, Generic)
+
+instance A.ToJSON Repeater where
+instance A.FromJSON Repeater where
+
+data DelayType = DelayAll | DelayFirst
+               deriving (Show, Eq, Generic)
+
+instance A.ToJSON   DelayType where
+instance A.FromJSON DelayType where
+
+data Delay = Delay {
+    delayType  :: DelayType
+  , delayValue :: Int
+  , delayUnit  :: TimeUnit
+  } deriving (Show, Eq, Generic)
+
+instance A.ToJSON Delay where
+instance A.FromJSON Delay where
+
+data TimeUnit = UnitYear
+              | UnitWeek
+              | UnitMonth
+              | UnitDay
+              | UnitHour
+              deriving (Show, Eq, Generic)
+
+instance A.ToJSON TimeUnit where
+instance A.FromJSON TimeUnit where
+
+---------------------------------------------------------------------------
+--instance A.ToJSON Document where
+--instance A.FromJSON Document where
+
+newtype StateKeyword = StateKeyword {unStateKeyword :: Text}
+  deriving (Show, Eq, Generic)
+
+instance A.ToJSON StateKeyword where
+instance A.FromJSON StateKeyword where
+
+
+data PlanningKeyword = SCHEDULED | DEADLINE | CLOSED
+  deriving (Show, Eq, Enum, Ord, Generic)
+
+instance A.ToJSON PlanningKeyword where
+instance A.FromJSON PlanningKeyword where
+
+--instance (A.ToJSON k, A.ToJSON v) => A.ToJSON (HashMap k v) where
+--  toJSON hm = A.object hm
+
+newtype Plannings = Plns (HashMap PlanningKeyword Timestamp)
+                  deriving (Show, Eq, Generic)
+
+instance A.ToJSON Plannings where
+  toJSON (Plns hm) = A.object $ map jPair (toList hm)
+    where jPair (k, v) = pack (show k) .= A.toJSON v
+
+instance A.FromJSON Plannings where
+  parseJSON (A.Object v) = Plns . fromList <$> (traverse jPair (keys v))
+    where jPair k = v .: k
+  parseJSON _ = mzero
+
+instance A.ToJSON Section where
+instance A.FromJSON Section where
+
+instance A.ToJSON Heading where
+instance A.FromJSON Heading where
+
+data Priority = A | B | C
+  deriving (Show, Read, Eq, Ord, Generic)
+
+instance A.ToJSON Priority where
+instance A.FromJSON Priority where
+type Tag = Text
+
+data Stats = StatsPct Int
+           | StatsOf  Int Int
+           deriving (Show, Eq, Generic)
+
+instance A.ToJSON Stats where
+instance A.FromJSON Stats where
+
+type Duration = (Hour,Minute)
+
+instance Hashable PlanningKeyword where
+  hashWithSalt salt k = hashWithSalt salt (fromEnum k)
+
+-- -- This might be the form to use if we were supporting <diary> timestamps
+-- data Timestamp = Dairy Text
+--                | Time  TimestampTime
+--               deriving (Show, Eq, Generic)
+
+
+
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -7,6 +7,7 @@
 import           PropertyDrawer
 import           Test.Tasty
 import           Timestamps
+import           Document
 
 main :: IO ()
 main = defaultMain tests
@@ -17,4 +18,5 @@
           [ parserHeadingTests
           , parserPropertyDrawerTests
           , parserTimestampTests
+          , parserSmallDocumentTests
           ]
