diff --git a/ipfs.cabal b/ipfs.cabal
--- a/ipfs.cabal
+++ b/ipfs.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           ipfs
-version:        1.2.0.0
+version:        1.3.0.0
 synopsis:       Access IPFS locally and remotely
 description:    Interact with the IPFS network by shelling out to a local IPFS node or communicating via the HTTP interface of a remote IPFS node.
 category:       Network
@@ -19,7 +19,7 @@
                 daniel@fission.codes,
                 steven@fission.codes,
                 james@fission.codes
-copyright:      © 2020 Fission Internet Software Services for Open Networks Inc.
+copyright:      © 2021 Fission Internet Software Services for Open Networks Inc.
 license:        Apache-2.0
 license-file:   LICENSE
 tested-with:
@@ -43,6 +43,8 @@
       Network.IPFS.Client
       Network.IPFS.Client.Add
       Network.IPFS.Client.Cat
+      Network.IPFS.Client.DAG.Put.Types
+      Network.IPFS.Client.DAG.Types
       Network.IPFS.Client.Error.Types
       Network.IPFS.Client.Param
       Network.IPFS.Client.Pin
@@ -53,6 +55,7 @@
       Network.IPFS.DAG.Link.Types
       Network.IPFS.DAG.Node.Types
       Network.IPFS.Error
+      Network.IPFS.File.Form.Types
       Network.IPFS.File.Types
       Network.IPFS.Gateway.Types
       Network.IPFS.Get
@@ -147,6 +150,7 @@
     , rio
     , servant
     , servant-client
+    , servant-multipart
     , servant-server
     , swagger2
     , text
@@ -224,6 +228,7 @@
     , rio
     , servant
     , servant-client
+    , servant-multipart
     , servant-server
     , swagger2
     , text
diff --git a/library/Network/IPFS/Client.hs b/library/Network/IPFS/Client.hs
--- a/library/Network/IPFS/Client.hs
+++ b/library/Network/IPFS/Client.hs
@@ -5,6 +5,7 @@
   , stat
   , pin
   , unpin
+  , dagPut
   ) where
 
 import qualified RIO.ByteString.Lazy                             as Lazy
@@ -15,11 +16,14 @@
 import           Network.IPFS.Prelude                            hiding (object)
 
 import           Network.IPFS.CID.Types
+import qualified Network.IPFS.File.Form.Types                    as File
 import qualified Network.IPFS.File.Types                         as File
 import           Network.IPFS.Stat.Types
 
 import qualified Network.IPFS.Client.Add                         as Add
 import qualified Network.IPFS.Client.Cat                         as Cat
+import qualified Network.IPFS.Client.DAG.Put.Types               as DAG.Put
+import qualified Network.IPFS.Client.DAG.Types                   as DAG
 import qualified Network.IPFS.Client.Pin                         as Pin
 import qualified Network.IPFS.Client.Stat                        as Stat
 
@@ -31,16 +35,18 @@
 type V0API = "add"    :> Add.API
         :<|> "cat"    :> Cat.API
         :<|> "object" :> Stat.API
+        :<|> "dag"    :> DAG.API
         :<|> "pin"    :> Pin.API
 
-add   :: Lazy.ByteString -> ClientM CID
-cat   :: CID             -> ClientM File.Serialized
-stat  :: CID             -> ClientM Stat
-pin   :: CID             -> ClientM Pin.Response
-unpin :: CID -> Bool     -> ClientM Pin.Response
+cat    :: CID                                         -> ClientM File.Serialized
+stat   :: CID                                         -> ClientM Stat
+pin    :: CID                                         -> ClientM Pin.Response
+unpin  :: CID -> Bool                                 -> ClientM Pin.Response
+dagPut ::        Bool -> (Lazy.ByteString, File.Form) -> ClientM DAG.Put.Response
+add    ::                 Lazy.ByteString             -> ClientM CID
 
 add :<|> cat
     :<|> stat
+    :<|> dagPut
     :<|> pin
-    :<|> unpin
-    = client $ Proxy @API
+    :<|> unpin = client $ Proxy @API
diff --git a/library/Network/IPFS/Client/DAG/Put/Types.hs b/library/Network/IPFS/Client/DAG/Put/Types.hs
new file mode 100644
--- /dev/null
+++ b/library/Network/IPFS/Client/DAG/Put/Types.hs
@@ -0,0 +1,22 @@
+module Network.IPFS.Client.DAG.Put.Types (API, Response (..)) where
+
+import           Servant.API
+import           Servant.Multipart
+
+import           Network.IPFS.Prelude
+
+import           Network.IPFS.CID.Types
+import qualified Network.IPFS.File.Form.Types as File
+
+type API
+  =  QueryParam' '[Required, Strict] "pin" Bool
+  :> MultipartForm Tmp File.Form
+  :> Post '[JSON] Response
+
+newtype Response = Response CID
+
+instance FromJSON Response where
+  parseJSON = withObject "IPFS.DAG.Response" \obj -> do
+    cidField <- obj .: "Cid"
+    cid      <- cidField .: "/"
+    return $ Response cid
diff --git a/library/Network/IPFS/Client/DAG/Types.hs b/library/Network/IPFS/Client/DAG/Types.hs
new file mode 100644
--- /dev/null
+++ b/library/Network/IPFS/Client/DAG/Types.hs
@@ -0,0 +1,9 @@
+module Network.IPFS.Client.DAG.Types (API) where
+
+import           Servant.API
+
+import qualified Network.IPFS.Client.DAG.Put.Types as Put
+
+type API
+  =  "put"
+  :> Put.API
diff --git a/library/Network/IPFS/DAG.hs b/library/Network/IPFS/DAG.hs
--- a/library/Network/IPFS/DAG.hs
+++ b/library/Network/IPFS/DAG.hs
@@ -1,25 +1,31 @@
 module Network.IPFS.DAG
   ( put
   , putNode
+  , putRemote
   ) where
 
-import Network.IPFS.Prelude
-import Network.IPFS.Local.Class as IPFS
+import           Data.ByteString.Lazy.Char8        as CL
+import qualified Network.IPFS.Internal.UTF8        as UTF8
+import qualified RIO.ByteString.Lazy               as Lazy
 
-import qualified Network.IPFS.Internal.UTF8 as UTF8
-import           Data.ByteString.Lazy.Char8 as CL
-import qualified RIO.ByteString.Lazy        as Lazy
+import           Servant.Client
+import qualified Servant.Multipart                 as Multipart
 
-import           Network.IPFS.Add.Error      as IPFS.Add
-import           Network.IPFS.Types          as IPFS
-import           Network.IPFS.DAG.Node.Types as DAG
+import           Network.IPFS.Prelude
 
-put :: 
-  MonadLocalIPFS m
-  => Lazy.ByteString
-  -> m (Either IPFS.Add.Error IPFS.CID)
+import           Network.IPFS.Add.Error            as IPFS.Add
+import qualified Network.IPFS.Client               as IPFS.Client
+import           Network.IPFS.Client.DAG.Put.Types as DAG.Put
+import           Network.IPFS.DAG.Node.Types       as DAG
+import           Network.IPFS.File.Form.Types      as File
+import           Network.IPFS.File.Types           as File
+import           Network.IPFS.Local.Class          as IPFS
+import           Network.IPFS.Remote.Class         as IPFS
+import           Network.IPFS.Types                as IPFS
+
+put :: MonadLocalIPFS m => Lazy.ByteString -> m (Either IPFS.Add.Error IPFS.CID)
 put raw = IPFS.runLocal ["dag", "put", "-f", "dag-pb"] raw >>= \case
-  Right result -> 
+  Right result ->
     case CL.lines result of
       [cid] ->
         cid
@@ -30,13 +36,15 @@
           |> return
 
       bad ->
-        pure . Left . UnexpectedOutput <| UTF8.textShow bad
+        pure . Left . UnexpectedOutput $ UTF8.textShow bad
 
-  Left err -> 
-    pure . Left . UnknownAddErr <| UTF8.textShow err
+  Left err ->
+    pure . Left . UnknownAddErr $ UTF8.textShow err
 
-putNode :: 
-  MonadLocalIPFS m
-  => DAG.Node
-  -> m (Either IPFS.Add.Error IPFS.CID)
-putNode node = put <| encode node
+putNode :: MonadLocalIPFS m => DAG.Node -> m (Either IPFS.Add.Error IPFS.CID)
+putNode node = put $ encode node
+
+putRemote :: MonadRemoteIPFS m => File.Serialized -> m (Either ClientError DAG.Put.Response)
+putRemote file = do
+  boundary  <- liftIO Multipart.genBoundary
+  runRemote (IPFS.Client.dagPut True (boundary, File.Form "file" file))
diff --git a/library/Network/IPFS/DAG/Node/Types.hs b/library/Network/IPFS/DAG/Node/Types.hs
--- a/library/Network/IPFS/DAG/Node/Types.hs
+++ b/library/Network/IPFS/DAG/Node/Types.hs
@@ -1,19 +1,19 @@
 module Network.IPFS.DAG.Node.Types (Node (..)) where
 
-import Network.IPFS.Prelude
+import           Network.IPFS.Prelude
 
-import Data.Vector
-import Network.IPFS.DAG.Link.Types as DAG
+import           Data.Vector
+import           Network.IPFS.DAG.Link.Types as DAG
 
 
 data Node = Node
   { dataBlock :: Text
-  , links :: [DAG.Link]
+  , links     :: [DAG.Link]
   } deriving (Show, Eq)
 
 instance ToJSON Node where
-  toJSON (Node dataBlock links) = 
+  toJSON (Node dataBlock links) =
     Object [ ("data", String dataBlock)
-           , ("links", Array . fromList <| toJSON <$> links)
+           , ("links", Array . fromList $ fmap toJSON links)
            ]
 
diff --git a/library/Network/IPFS/File/Form/Types.hs b/library/Network/IPFS/File/Form/Types.hs
new file mode 100644
--- /dev/null
+++ b/library/Network/IPFS/File/Form/Types.hs
@@ -0,0 +1,23 @@
+module Network.IPFS.File.Form.Types (Form (..)) where
+
+import           RIO
+import qualified RIO.ByteString.Lazy     as Lazy
+
+import           Servant.Multipart
+
+import qualified Network.IPFS.File.Types as File
+
+data Form = Form
+  { name       :: Text
+  , serialized :: File.Serialized
+  }
+
+instance ToMultipart Tmp Form where
+  toMultipart Form { name = name, serialized = File.Serialized fileLBS } =
+    MultipartData
+        [ Input
+          { iName  = name
+          , iValue = decodeUtf8Lenient $ Lazy.toStrict fileLBS
+          }
+        ]
+        []
