diff --git a/serverless-haskell.cabal b/serverless-haskell.cabal
--- a/serverless-haskell.cabal
+++ b/serverless-haskell.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 8744fabb134bae654aeb0568028f9f99e96f2f7feeb7526d6c85b95685022f8e
+-- hash: 9f8f42c39c47eb860db76ff109b447b37326ae914e1e88eaccbcb7f6734e00e8
 
 name:           serverless-haskell
-version:        0.0.6
+version:        0.1.0
 synopsis:       Deploying Haskell code onto AWS Lambda using Serverless
 description:    Utilities to help process the events from AWS Lambda when deployed with the serverless-haskell plugin.
 category:       AWS, Cloud, Network
@@ -44,6 +44,7 @@
   exposed-modules:
       AWSLambda
       AWSLambda.Events
+      AWSLambda.Events.Embedded
       AWSLambda.Events.KinesisEvent
       AWSLambda.Events.Records
       AWSLambda.Events.S3Event
diff --git a/src/AWSLambda/Events.hs b/src/AWSLambda/Events.hs
--- a/src/AWSLambda/Events.hs
+++ b/src/AWSLambda/Events.hs
@@ -10,41 +10,59 @@
 import           AWSLambda.Events.S3Event
 import           AWSLambda.Events.SNSEvent
 
+-- | Not yet implemented
 data DynamoDBEvent
 
+-- | Not yet implemented
 data SESEvent
 
+-- | Not yet implemented
 data CognitoEvent
 
+-- | Not yet implemented
 data CloudFormationEvent
 
+-- | Not yet implemented
 data CloudWatchLogsEvent
 
+-- | Not yet implemented
 data CloudWatchEventsEvent
 
+-- | Not yet implemented
 data CodeCommitEvent
 
+-- | Not yet implemented
 data ConfigEvent
 
+-- | Not yet implemented
 data AlexaEvent
 
+-- | Not yet implemented
 data LexEvent
 
+-- | Not yet implemented
 data APIGatewayEvent
 
+-- | Not yet implemented
 data IoTButtonEvent
 
+-- | Not yet implemented
 data CloudFrontEvent
 
+-- | Not yet implemented
 data FirehoseEvent
 
+-- | Not yet implemented
 data InvokeEvent
 
-data LambdaEvent
+-- | Sum type for all possible Lambda events.
+-- Parameterised on the type of SNS Events to be handled.
+-- See @SNSEvent@ for details.
+data LambdaEvent snsMessage
   = S3 !S3Event
   | DynamoDB !DynamoDBEvent
   | KinesisStream !KinesisEvent
-  | SNS !SNSEvent
+  | SNS !(SNSEvent snsMessage)
   | SES !SESEvent
   | Cognito !CognitoEvent
   | CloudFormation !CloudFormationEvent
@@ -61,7 +79,14 @@
   | Invoke !InvokeEvent
   | Custom !Value
 
-instance FromJSON LambdaEvent where
-  parseJSON v = S3 <$> parseJSON v <|> pure (Custom v)
+-- | Attempt to parse the various event types.
+-- Any valid JSON that can't be parsed as a specific
+-- event type will result in a 'Custom' value.
+instance FromJSON snsMessage =>
+         FromJSON (LambdaEvent snsMessage) where
+  parseJSON v =
+    try S3 v <|> try KinesisStream v <|> try SNS v <|> pure (Custom v)
+    where
+      try f = fmap f . parseJSON
 
 $(makePrisms ''LambdaEvent)
diff --git a/src/AWSLambda/Events/Embedded.hs b/src/AWSLambda/Events/Embedded.hs
new file mode 100644
--- /dev/null
+++ b/src/AWSLambda/Events/Embedded.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE TemplateHaskell   #-}
+
+{-|
+Module: AWSLambda.Events.Embedded
+Description: Type for a JSON value embedded within a JSON string value
+-}
+module AWSLambda.Events.Embedded where
+
+import           Control.Lens.TH
+import           Data.Aeson
+import Data.Text.Encoding        (encodeUtf8)
+
+-- | Type for a JSON value embedded within a JSON string value
+newtype Embedded a = Embedded { _unEmbed :: a } deriving (Eq, Show)
+
+instance FromJSON a =>
+         FromJSON (Embedded a) where
+  parseJSON =
+    withText "Embedded JSON" $
+    fmap Embedded . either fail pure . eitherDecodeStrict . encodeUtf8
+
+$(makeLenses ''Embedded)
diff --git a/src/AWSLambda/Events/SNSEvent.hs b/src/AWSLambda/Events/SNSEvent.hs
--- a/src/AWSLambda/Events/SNSEvent.hs
+++ b/src/AWSLambda/Events/SNSEvent.hs
@@ -27,8 +27,8 @@
 $(deriveFromJSON (aesonDrop 3 pascalCase) ''MessageAttribute)
 $(makeLenses ''MessageAttribute)
 
-data SNSMessage = SNSMessage
-  { _smMessage           :: !Text
+data SNSMessage message = SNSMessage
+  { _smMessage           :: !message
   , _smMessageAttributes :: !(HashMap Text MessageAttribute)
   , _smMessageId         :: !Text
   , _smSignature         :: !Text
@@ -44,14 +44,20 @@
 $(deriveFromJSON (aesonDrop 3 pascalCase) ''SNSMessage)
 $(makeLenses ''SNSMessage)
 
-data SNSRecord = SNSRecord
+data SNSRecord message = SNSRecord
   { _srEventVersion         :: !Text
   , _srEventSubscriptionArn :: !Text
   , _srEventSource          :: !Text
-  , _srSns                  :: !SNSMessage
+  , _srSns                  :: !(SNSMessage message)
   } deriving (Eq, Show)
 
 $(deriveFromJSON (aesonDrop 3 pascalCase) ''SNSRecord)
 $(makeLenses ''SNSRecord)
 
-type SNSEvent = RecordsEvent SNSRecord
+-- | SNSEvent.
+-- The 'message' type is parameterised. To treat it as a text value
+-- use @SNSEvent Text@.
+-- To extract an embedded event object use the 'Embedded' type.
+-- E.g. @SNSEvent (Embedded S3Event)@ will treat the message
+-- as an embedded S3Event.
+type SNSEvent message = RecordsEvent (SNSRecord message)
diff --git a/test/AWSLambda/Events/SNSEventSpec.hs b/test/AWSLambda/Events/SNSEventSpec.hs
--- a/test/AWSLambda/Events/SNSEventSpec.hs
+++ b/test/AWSLambda/Events/SNSEventSpec.hs
@@ -3,14 +3,19 @@
 
 module AWSLambda.Events.SNSEventSpec where
 
+import           AWSLambda.Events.Embedded
 import           AWSLambda.Events.Records
+import           AWSLambda.Events.S3Event
 import           AWSLambda.Events.SNSEvent
 
 import           Data.Aeson
 import           Data.ByteString.Lazy      (ByteString)
 import qualified Data.HashMap.Strict       as HashMap
+import           Data.Text                 (Text)
 import           Data.Time.Calendar
 import           Data.Time.Clock
+import           Network.AWS.S3            as S3
+import           Network.AWS.Types         as AWS
 
 import           Text.RawString.QQ
 
@@ -18,9 +23,11 @@
 
 spec :: Spec
 spec =
-  describe "SNSEvent" $
-    it "parses sample event" $
+  describe "SNSEvent" $ do
+    it "parses sample text event" $
       decode sampleSNSJSON `shouldBe` Just sampleSNSEvent
+    it "parses sample embedded S3 event" $
+      decode sampleSNSS3JSON `shouldBe` Just sampleSNSS3Event
 
 sampleSNSJSON :: ByteString
 sampleSNSJSON = [r|
@@ -57,7 +64,7 @@
 }
 |]
 
-sampleSNSEvent :: SNSEvent
+sampleSNSEvent :: SNSEvent Text
 sampleSNSEvent =
   RecordsEvent
     [ SNSRecord
@@ -92,3 +99,109 @@
         }
       }
     ]
+
+sampleSNSS3JSON :: ByteString
+sampleSNSS3JSON = [r|
+{"Records":
+  [
+    {"EventSource":"aws:sns",
+      "EventVersion":"1.0",
+      "EventSubscriptionArn":"arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent:23e2d254-e8bb-4db5-92ce-d917e5aad090",
+      "Sns":{
+        "Type":"Notification",
+        "MessageId":"89f6fe8b-a751-5dcd-8e0c-afbd75420455",
+        "TopicArn":"arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent",
+        "Subject":"Amazon S3 Notification",
+        "Message": "{\"Records\":[{\"eventVersion\":\"2.0\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"ap-southeast-2\",\"eventTime\":\"2017-03-06T02:56:19.713Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"AWS:DFLKSDFLKJ987SDFLJJDJ:some-principal-id\"},\"requestParameters\":{\"sourceIPAddress\":\"192.168.0.1\"},\"responseElements\":{\"x-amz-request-id\":\"324098EDFLK0894F\",\"x-amz-id-2\":\"xsdSDF/pgAl401Fz3UIATJ5/didfljDSFDSFsdfkjsdfl8JdsfLSDF89ldsf7SDF898jsdfljiA=\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"SomeS3Event:Created\",\"bucket\":{\"name\":\"some-bucket\",\"ownerIdentity\":{\"principalId\":\"A3O1SDFLKJIJXU\"},\"arn\":\"arn:aws:s3:::some-bucket\"},\"object\":{\"key\":\"path/to/some/object\",\"size\":53598442,\"eTag\":\"6b1f72b9e81e4d6fcd3e0c808e8477f8\",\"sequencer\":\"0058BCCFD25C798E7B\"}}}]}",
+        "Timestamp":"2017-03-06T02:56:19.834Z",
+        "SignatureVersion":"1",
+        "Signature":"aybEgnTjKzSbC2puHxho7SUnYOje4SjBoCyt0Q13bMWyp7M64+EU6jzi7P01+gSIuBFyYPsHreSmyqGMRSxbFuzn7rG5JcVGN0901U3CRXdk42eh03je8evRvs/Oa7TJlhpCTEDDOScalCWbIH0RthYONQpPR01nEgaNKj3e8YVJqyRQV+4RbU3YWJOj+Spyi4u1hOC9PLUv4BH7U80nbhbOe9EwgX0zpeNU1WBRbEpqPoACm+7/uB0w79qFBKjB/Q7OWc1kASUZV9q8bz03yceoQeVvza0QGhPsnSXi49sn1mLWQOFS4KvgbJIC/Qk7H036ShrDioP6pP+UEg6kow==",
+        "SigningCertUrl":"https://sns.ap-southeast-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem",
+        "UnsubscribeUrl":"https://sns.ap-southeast-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent:23e2d254-e8bb-4db5-92ce-d917e5aad090",
+        "MessageAttributes":{}
+      }
+    }
+  ]
+}
+|]
+
+sampleSNSS3Event :: SNSEvent (Embedded S3Event)
+sampleSNSS3Event =
+  RecordsEvent
+  { _reRecords =
+    [ SNSRecord
+      { _srEventVersion = "1.0"
+      , _srEventSubscriptionArn =
+        "arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent:23e2d254-e8bb-4db5-92ce-d917e5aad090"
+      , _srEventSource = "aws:sns"
+      , _srSns =
+        SNSMessage
+        { _smMessage =
+          Embedded
+          { _unEmbed =
+            RecordsEvent
+            { _reRecords =
+              [ S3EventNotification
+                { _senAwsRegion = Sydney
+                , _senEventName = S3ObjectCreatedPut
+                , _senEventSource = "aws:s3"
+                , _senEventTime = UTCTime (fromGregorian 2017 3 6) (picosecondsToDiffTime 10579713000000000)
+                , _senEventVersion = "2.0"
+                , _senRequestParameters =
+                  RequestParametersEntity
+                  { _rpeSourceIPAddress = "192.168.0.1"
+                  }
+                , _senResponseElements =
+                  ResponseElementsEntity
+                  { _reeXAmzId2 =
+                    "xsdSDF/pgAl401Fz3UIATJ5/didfljDSFDSFsdfkjsdfl8JdsfLSDF89ldsf7SDF898jsdfljiA="
+                  , _reeXAmzRequestId = "324098EDFLK0894F"
+                  }
+                , _senS3 =
+                  S3Entity
+                  { _seBucket =
+                    S3BucketEntity
+                    { _sbeArn = "arn:aws:s3:::some-bucket"
+                    , _sbeName = BucketName "some-bucket"
+                    , _sbeOwnerIdentity =
+                      UserIdentityEntity
+                      { _uiePrincipalId = "A3O1SDFLKJIJXU"
+                      }
+                    }
+                  , _seConfigurationId = "SomeS3Event:Created"
+                  , _seObject =
+                    S3ObjectEntity
+                    { _soeETag = Just (ETag "6b1f72b9e81e4d6fcd3e0c808e8477f8")
+                    , _soeKey = ObjectKey "path/to/some/object"
+                    , _soeSize = Just 53598442
+                    , _soeSequencer = "0058BCCFD25C798E7B"
+                    , _soeVersionId = Nothing
+                    }
+                  , _seS3SchemaVersion = "1.0"
+                  }
+                , _senUserIdentity =
+                  UserIdentityEntity
+                  { _uiePrincipalId =
+                    "AWS:DFLKSDFLKJ987SDFLJJDJ:some-principal-id"
+                  }
+                }
+              ]
+            }
+          }
+        , _smMessageAttributes = HashMap.fromList []
+        , _smMessageId = "89f6fe8b-a751-5dcd-8e0c-afbd75420455"
+        , _smSignature =
+          "aybEgnTjKzSbC2puHxho7SUnYOje4SjBoCyt0Q13bMWyp7M64+EU6jzi7P01+gSIuBFyYPsHreSmyqGMRSxbFuzn7rG5JcVGN0901U3CRXdk42eh03je8evRvs/Oa7TJlhpCTEDDOScalCWbIH0RthYONQpPR01nEgaNKj3e8YVJqyRQV+4RbU3YWJOj+Spyi4u1hOC9PLUv4BH7U80nbhbOe9EwgX0zpeNU1WBRbEpqPoACm+7/uB0w79qFBKjB/Q7OWc1kASUZV9q8bz03yceoQeVvza0QGhPsnSXi49sn1mLWQOFS4KvgbJIC/Qk7H036ShrDioP6pP+UEg6kow=="
+        , _smSignatureVersion = "1"
+        , _smSigningCertUrl =
+          "https://sns.ap-southeast-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem"
+        , _smSubject = "Amazon S3 Notification"
+        , _smTimestamp = UTCTime (fromGregorian 2017 3 6) (picosecondsToDiffTime 10579834000000000)
+        , _smTopicArn = "arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent"
+        , _smType = "Notification"
+        , _smUnsubscribeUrl =
+          "https://sns.ap-southeast-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-southeast-2:012345678901:SomeSNSEvent:23e2d254-e8bb-4db5-92ce-d917e5aad090"
+        }
+      }
+    ]
+  }
