diff --git a/haskell-neo4j-client.cabal b/haskell-neo4j-client.cabal
--- a/haskell-neo4j-client.cabal
+++ b/haskell-neo4j-client.cabal
@@ -1,11 +1,11 @@
 name:                haskell-neo4j-client
-version:             0.1.0.0
+version:             0.1.5.0
 synopsis:            A Haskell neo4j client
 description:         
     Library to interact with Neo4j databases. For now, its API covers basic operations for nodes, relationships, labels
     and indexes and provides calls to use these in batch mode.
     .
-    Cypher is not yet supported, but it hopefully will be very soon.
+    Basic support for Cypher implemented
     .
     All code has been tested with Neo4j version 2.0.3
 homepage:            https://github.com/asilvestre/haskell-neo4j-rest-client
@@ -47,7 +47,7 @@
                      mtl ==2.2.*
 library
   hs-source-dirs:      src
-  exposed-modules:     Database.Neo4j, Database.Neo4j.Graph, Database.Neo4j.Batch
+  exposed-modules:     Database.Neo4j, Database.Neo4j.Graph, Database.Neo4j.Batch, Database.Neo4j.Cypher
   other-modules:       Database.Neo4j.Types, Database.Neo4j.Http, Database.Neo4j.Node, Database.Neo4j.Relationship,
                        Database.Neo4j.Property, Database.Neo4j.Label, Database.Neo4j.Index, Database.Neo4j.Batch.Node,
                        Database.Neo4j.Batch.Relationship, Database.Neo4j.Batch.Property, Database.Neo4j.Types,
diff --git a/src/Database/Neo4j.hs b/src/Database/Neo4j.hs
--- a/src/Database/Neo4j.hs
+++ b/src/Database/Neo4j.hs
@@ -107,3 +107,23 @@
 -- instance 'Neo4jNoEntityException', or more generic ones like 'Neo4jHttpException' or 'Neo4jParseException'
 -- if the server  returns something totally unexpected. (I'm sure there's still work to do here preparing the code
 -- to return more specific exceptions for known scenarios)
+-- 
+-- About Cypher support for now we allow sending queries with parameters, the result is a collection of column headers
+-- and JSON data values, the Graph object has the function addCypher that tries to find
+-- nodes and relationships in a cypher query result and insert them in a "Database.Neo4j.Graph" object
+--
+-- > import qualified Database.Neo4j.Cypher as C
+-- >
+-- > withConnection host port $ do
+-- >    ...
+-- >    -- Run a cypher query with parameters
+-- >    res <- C.cypher "CREATE (n:Person { name : {name} }) RETURN n" M.fromList [("name", C.newparam ("Pep" :: T.Text))]
+-- >
+-- >    -- Get all nodes and relationships that this query returned and insert them in a Graph object
+-- >    let graph = G.addCypher (C.fromSuccess res) G.empty
+-- >
+-- >    -- Get the column headers
+-- >    let columnHeaders = C.cols $ C.fromSuccess res
+-- >
+-- >    -- Get the rows of JSON values received
+-- >    let values = C.vals $ C.fromSuccess res
diff --git a/src/Database/Neo4j/Cypher.hs b/src/Database/Neo4j/Cypher.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/Neo4j/Cypher.hs
@@ -0,0 +1,88 @@
+{-# LANGUAGE OverloadedStrings  #-}
+
+-- | Module to provide Cypher support.
+--  Currently we allow sending queries with parameters, the result is a collection of column headers
+--  and JSON data values, the Graph object has the function addCypher that tries to find
+--  nodes and relationships in a cypher query result and insert them in a "Database.Neo4j.Graph" object
+--
+-- > import qualified Database.Neo4j.Cypher as C
+-- >
+-- > withConnection host port $ do
+-- >    ...
+-- >    -- Run a cypher query with parameters
+-- >    res <- C.cypher "CREATE (n:Person { name : {name} }) RETURN n" M.fromList [("name", C.newparam ("Pep" :: T.Text))]
+-- >
+-- >    -- Get all nodes and relationships that this query returned and insert them in a Graph object
+-- >    let graph = G.addCypher (C.fromSuccess res) G.empty
+-- >
+-- >    -- Get the column headers
+-- >    let columnHeaders = C.cols $ C.fromSuccess res
+-- >
+-- >    -- Get the rows of JSON values received
+-- >    let values = C.vals $ C.fromSuccess res
+module Database.Neo4j.Cypher (
+    -- * Types
+    Response(..), ParamValue(..), Params, newparam,
+    -- * Sending queries
+    cypher, fromResult, fromSuccess, isSuccess
+    ) where
+
+import Data.Aeson ((.=), (.:))
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (mzero)
+
+import qualified Data.Aeson as J
+import qualified Data.ByteString as S
+import qualified Data.HashMap.Lazy as M
+import qualified Data.Text as T
+
+import Database.Neo4j.Types
+import Database.Neo4j.Http
+
+-- | Type for a Cypher response with tuples containing column name and their values
+data Response = Response {cols :: [T.Text], vals :: [[J.Value]]} deriving (Show, Eq)
+
+-- | How to create a response object from a cypher JSON response
+instance J.FromJSON Response where
+    parseJSON (J.Object o) = Response <$> (o .: "columns" >>= J.parseJSON) <*> (o .: "data" >>= J.parseJSON)
+    parseJSON _ = mzero
+                        
+cypherAPI :: S.ByteString
+cypherAPI = "/db/data/cypher"
+
+-- | Value for a cypher parmeter value, might be a literal, a property map or a list of property maps
+data ParamValue = ParamLiteral PropertyValue | ParamProperties Properties | ParamPropertiesArray [Properties]
+     deriving (Show, Eq)
+
+newparam :: PropertyValueConstructor a => a -> ParamValue
+newparam = ParamLiteral . newval
+
+-- | Instance toJSON for param values so we can serialize them in queries
+instance J.ToJSON ParamValue where
+    toJSON (ParamLiteral l) = J.toJSON l
+    toJSON (ParamProperties p) = J.toJSON p
+    toJSON (ParamPropertiesArray ps) = J.toJSON ps
+
+-- | We use hashmaps to represent Cypher parameters
+type Params = M.HashMap T.Text ParamValue
+
+-- | Run a cypher query
+cypher :: T.Text -> Params -> Neo4j (Either T.Text Response)
+cypher cmd params = Neo4j $ \conn -> httpCreate4XXExplained conn cypherAPI body
+    where body = J.encode $ J.object ["query" .= cmd, "params" .= J.toJSON params]
+
+-- | Get the result of the response or a default value
+fromResult :: Response -> Either T.Text Response -> Response
+fromResult def (Left _) = def
+fromResult _ (Right resp) = resp
+
+-- | Get the result of the response or a default value
+fromSuccess :: Either T.Text Response -> Response
+fromSuccess (Left _) = error "Cypher.fromSuccess but is Error"
+fromSuccess (Right resp) = resp
+
+-- | True if the operation succeeded
+isSuccess :: Either T.Text Response -> Bool
+isSuccess (Left _) = False
+isSuccess (Right _) = True
+
diff --git a/src/Database/Neo4j/Graph.hs b/src/Database/Neo4j/Graph.hs
--- a/src/Database/Neo4j/Graph.hs
+++ b/src/Database/Neo4j/Graph.hs
@@ -21,6 +21,8 @@
     setProperties, setProperty, deleteProperties, deleteProperty,
     -- * Handling labels
     setNodeLabels, addNodeLabel, getNodeLabels, deleteNodeLabel,
+    -- * Handling Cypher results
+    addCypher,
     -- * Graph filtering functions
     nodeFilter, relationshipFilter,
     -- * Graph operations
@@ -29,11 +31,15 @@
 
 import Data.Maybe (fromMaybe)
 
+import Control.Applicative ((<$>), (<*>))
+import qualified Data.Aeson as J
 import qualified Data.HashMap.Lazy as M
 import qualified Data.HashSet as HS
+import qualified Data.List as L
 import qualified Data.Text as T
 
 import Database.Neo4j.Types
+import qualified Database.Neo4j.Cypher as C
 
 type NodeIndex = M.HashMap NodePath Node
 type RelIndex = M.HashMap RelPath Relationship
@@ -213,3 +219,16 @@
 intersection ga gb = relationshipFilter relFilterFunc (nodeFilter nodeFilterFunc ga)
     where relFilterFunc r = hasRelationship r gb
           nodeFilterFunc n = hasNode n gb
+
+-- | Feed a cypher result into a graph (looks for nodes and relationships and inserts them)
+addCypher :: C.Response -> Graph -> Graph
+addCypher (C.Response _ vals) ginit = foldl tryAdd ginit (concat vals)
+    where tryAdd :: Graph -> J.Value -> Graph
+          -- Try first to parse it as a relationship and then as a node, otherwise leave the graph as it is
+          tryAdd g v = fromMaybe g $ L.find parseSuccess (map ($ v) [relParser g, nodeParser g]) >>= fromResult
+          relParser g v = flip addRelationship g <$> J.fromJSON v
+          nodeParser g v = flip addNode g <$> J.fromJSON v
+          parseSuccess (J.Success _) = True
+          parseSuccess (J.Error _) = False
+          fromResult (J.Error _) = Nothing
+          fromResult (J.Success g) = Just g
diff --git a/src/Database/Neo4j/Http.hs b/src/Database/Neo4j/Http.hs
--- a/src/Database/Neo4j/Http.hs
+++ b/src/Database/Neo4j/Http.hs
@@ -85,12 +85,14 @@
 --   With 404 or 400 will return a left with the explanation
 httpCreate4XXExplained :: J.FromJSON a => Connection -> S.ByteString -> L.ByteString -> ResourceT IO (Either T.Text a)
 httpCreate4XXExplained conn path body = do
-            res <- httpReq conn HT.methodPost path body (\s -> s `elem` [HT.status201, HT.status404, HT.status400])
+            res <- httpReq conn HT.methodPost path body (\s -> s `elem` validcodes ++ errcodes)
             let status = HC.responseStatus res
-            return $ if status == HT.status201 then parseBody res else Left $ extractException res
+            return $ if status `elem`  validcodes then parseBody res else Left $ extractException res
     where parseBody resp = case J.eitherDecode $ HC.responseBody resp of
                             Right entity -> Right entity
                             Left e -> throw $ Neo4jParseException ("Error parsing created entity: " ++ e)
+          validcodes = [HT.status200, HT.status201]
+          errcodes = [HT.status404, HT.status400]
 
 -- | Launch a POST request that doesn't expect response body, this will raise an exception if 204 is not received
 httpCreate_ :: Connection -> S.ByteString -> L.ByteString -> ResourceT IO ()
diff --git a/tests/IntegrationTests.hs b/tests/IntegrationTests.hs
--- a/tests/IntegrationTests.hs
+++ b/tests/IntegrationTests.hs
@@ -7,11 +7,13 @@
 import Data.Int (Int64)
 import Data.Maybe (fromJust)
 
+import qualified Data.Aeson as J
 import qualified Data.ByteString as S
 import qualified Data.HashMap.Lazy as M
 import qualified Data.HashSet as HS
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
+import qualified Data.Vector as V
 
 import Control.Exception (handle)
 import Test.Framework.TH (defaultMainGenerator)
@@ -19,8 +21,9 @@
 import Test.HUnit.Base hiding (Test, Node)
 
 import Database.Neo4j
-import qualified Database.Neo4j.Graph as G
 import qualified Database.Neo4j.Batch as B
+import qualified Database.Neo4j.Cypher as C
+import qualified Database.Neo4j.Graph as G
 
 (<>) :: Monoid a => a -> a -> a
 (<>) = mappend
@@ -1175,3 +1178,174 @@
         return ()
     where lbl1 = "lbl1"
           lbl2 = "lbl2"
+
+-- | Test cypher basic test
+case_cypherBasic :: Assertion
+case_cypherBasic = withConnection host port $ do
+        -- create initial data
+        gp <- B.runBatch $ do
+            n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
+            n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
+            B.createRelationship "know" M.empty n1 n2
+        -- actual test
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        neo4jEqual ["TYPE(r)"] (C.cols $ C.fromSuccess res)
+        neo4jBool $ ["know"] `elem` (C.vals $ C.fromSuccess res)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "MATCH (x {name: {startName}})-[r]-(friend) WHERE friend.name = {name} RETURN TYPE(r)"
+          params = M.fromList [("startName", C.newparam ("I" :: T.Text)), ("name", C.newparam ("you" :: T.Text))]
+
+
+-- | Test cypher create a node
+case_cypherCreateNode :: Assertion
+case_cypherCreateNode = withConnection host port $ do
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        let gp = G.addCypher (C.fromSuccess res) G.empty
+        let props = M.fromList ["name" |: ("Andres" :: T.Text)]
+        neo4jEqual 1 (length $ G.getNodes gp)
+        neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "CREATE (n:Person { name : {name} }) RETURN n"
+          params = M.fromList [("name", C.newparam ("Andres" :: T.Text))]
+
+-- | Test cypher create a node with multiple properties
+case_cypherCreateNodeMultipleProperties :: Assertion
+case_cypherCreateNodeMultipleProperties = withConnection host port $ do
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        let gp = G.addCypher (C.fromSuccess res) G.empty
+        neo4jEqual 1 (length $ G.getNodes gp)
+        neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "CREATE (n:Person { props }) RETURN n"
+          props = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text),
+                              "awesome" |: True, "children" |: (3 :: Int64)]
+          params = M.fromList [("props", C.ParamProperties props)]
+
+-- | Test cypher create multiple nodes
+case_cypherCreateMultipleNodes :: Assertion
+case_cypherCreateMultipleNodes = withConnection host port $ do
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        let gp = G.addCypher (C.fromSuccess res) G.empty
+        neo4jEqual 2 (length $ G.getNodes gp)
+        neo4jBool $ propsA `elem` map getNodeProperties (G.getNodes gp)
+        neo4jBool $ propsB `elem` map getNodeProperties (G.getNodes gp)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "CREATE (n:Person { props }) RETURN n"
+          propsA = M.fromList ["name" |: ("Andres" :: T.Text), "position" |: ("Developer" :: T.Text)]
+          propsB = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text)]
+          params = M.fromList [("props", C.ParamPropertiesArray [propsA, propsB])]
+
+-- | Test cypher set all properties on a node
+case_cypherSetAllNodeProperties :: Assertion
+case_cypherSetAllNodeProperties = withConnection host port $ do
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        let gp = G.addCypher (C.fromSuccess res) G.empty
+        neo4jEqual 1 (length $ G.getNodes gp)
+        neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "CREATE (n:Person { name: 'this property is to be deleted' } ) SET n = { props } RETURN n"
+          props = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text),
+                              "awesome" |: True, "children" |: (3 :: Int64)]
+          params = M.fromList [("props", C.ParamProperties props)]
+
+-- | Test cypher basic query
+case_cypherBasicQuery :: Assertion
+case_cypherBasicQuery = withConnection host port $ do
+        -- create initial data
+        gp <- B.runBatch $ do
+            n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
+            n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
+            n3 <- B.createNode $ M.fromList ["name" |: ("him" :: T.Text), "age" |: (25 :: Int64)]
+            _ <- B.createRelationship "know" M.empty n1 n2
+            B.createRelationship "know" M.empty n1 n3
+        -- actual test
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        neo4jEqual ["type(r)", "n.name", "n.age"] (C.cols $ C.fromSuccess res)
+        neo4jBool $ ["know", "him", J.Number 25] `elem` (C.vals $ C.fromSuccess res)
+        neo4jBool $ ["know", "you", J.Null] `elem` (C.vals $ C.fromSuccess res)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "MATCH (x {name: 'I'})-[r]->(n) RETURN type(r), n.name, n.age"
+          params = M.empty
+
+-- | Test cypher basic query get relationships
+case_cypherBasicQueryGetRels :: Assertion
+case_cypherBasicQueryGetRels = withConnection host port $ do
+        -- create initial data
+        gp <- B.runBatch $ do
+            n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
+            n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
+            n3 <- B.createNode $ M.fromList ["name" |: ("him" :: T.Text), "age" |: (25 :: Int64)]
+            _ <- B.createRelationship "know" M.empty n1 n2
+            B.createRelationship "know" M.empty n1 n3
+        -- actual test
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        let gres = G.addCypher (C.fromSuccess res) G.empty
+        neo4jBool $ (length $ G.getRelationships gres) >= 2
+        neo4jBool $ all (\r -> getRelType r == "know") (G.getRelationships gres)
+        neo4jEqual ["r"] (C.cols $ C.fromSuccess res)
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "MATCH (x {name: 'I'})-[r]->(n) RETURN r"
+          params = M.empty
+
+-- | Test cypher nested results
+case_cypherNestedResults :: Assertion
+case_cypherNestedResults = withConnection host port $ do
+        -- create initial data
+        gp <- B.runBatch $ do
+            n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
+            n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
+            B.createRelationship "know" M.empty n1 n2
+        -- actual test
+        res <- C.cypher query params
+        neo4jBool $ C.isSuccess res
+        neo4jEqual ["collect(n.name)"] (C.cols $ C.fromSuccess res)
+        let v = case (head $ head $ C.vals $ C.fromSuccess res) of
+                 J.Array vec -> vec
+                 _ -> V.empty
+        neo4jBool $ "you" `V.elem` v
+        neo4jBool $ "I" `V.elem` v
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "MATCH (n) WHERE n.name in ['I', 'you'] RETURN collect(n.name)"
+          params = M.empty
+
+-- | Test cypher errors
+case_cypherError :: Assertion
+case_cypherError = withConnection host port $ do
+        -- create initial data
+        gp <- B.runBatch $ do
+            B.createNode $ M.fromList ["age" |: (26 :: Int64)]
+        -- actual test
+        res <- C.cypher query params
+        neo4jEqual (Left "BadInputException") res
+        -- cleanup
+        _ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
+        return ()
+    where query = "MATCH (x) WHERE has(x.age) RETURN x.age / 0"
+          params = M.empty
