diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@
 
 ## [Unreleased]
 
+## [0.7.0] - 2022-01-12
+
+- Support Cachix Deploy
+
 ## [0.6.0] - 2021-01-08
 
 - Support latest stackage nightly
diff --git a/cachix-api.cabal b/cachix-api.cabal
--- a/cachix-api.cabal
+++ b/cachix-api.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               cachix-api
-version: 0.6.0
+version: 0.7.0
 synopsis:           Servant HTTP API specification for https://cachix.org
 homepage:           https://github.com/cachix/cachix#readme
 bug-reports:        https://github.com/cachix/cachix/issues
@@ -38,11 +38,15 @@
   import:          defaults
   exposed-modules:
     Cachix.API
+    Cachix.API.Deploy
     Cachix.API.Error
     Cachix.API.Signing
+    Cachix.API.WebSocketSubprotocol
     Cachix.Types.BinaryCache
     Cachix.Types.ByteStringStreaming
     Cachix.Types.ContentTypes
+    Cachix.Types.Deploy
+    Cachix.Types.DeployResponse
     Cachix.Types.NarFileName
     Cachix.Types.NarInfo
     Cachix.Types.NarInfoCreate
@@ -56,6 +60,7 @@
   hs-source-dirs:  src
   build-depends:
     , aeson
+    , async
     , base                  >=4.7    && <5
     , base16-bytestring
     , bytestring
@@ -81,6 +86,9 @@
     , text
     , time
     , transformers
+    , unordered-containers
+    , uuid
+    , websockets
 
 test-suite cachix-api-test
   import:             defaults
diff --git a/src/Cachix/API.hs b/src/Cachix/API.hs
--- a/src/Cachix/API.hs
+++ b/src/Cachix/API.hs
@@ -31,99 +31,98 @@
 type CachixAuth = Auth '[Cookie, JWT, BasicAuth] Session
 
 -- Nix CLI + Cachix CLI
-data BinaryCacheAPI route
-  = BinaryCacheAPI
-      { -- https://cache.nixos.org/nix-cache-info
-        nixCacheInfo ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "nix-cache-info"
-            :> Get '[XNixCacheInfo, JSON] NixCacheInfo.NixCacheInfo,
-        -- Hydra: src/lib/Hydra/View/NARInfo.pm
-        narinfo ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> Capture "narinfohash" NarInfoHash.NarInfoHash
-            :> Get '[XNixNarInfo, JSON] NarInfo.CachixNarInfo,
-        narinfoHead ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> Capture "narinfohash" NarInfoHash.NarInfoHash
-            :> Head,
-        -- Hydra: src/lib/Hydra/View/NixNAR.pm
-        nar ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "nar"
-            :> Capture "nar" NarFileName
-            :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ()),
-        -- cachix specific
-        getCache ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> Get '[JSON] BinaryCache.BinaryCache,
-        narinfoBulk ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "narinfo"
-            :> Summary "Given a list of store hashes, return a list of those that are missing"
-            :> ReqBody '[JSON] [Text]
-            :> Post '[JSON] [Text],
-        narURL ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "narurl"
-            :> Capture "nar" NarFileName
-            :> Get '[JSON] Text,
-        createNarinfo ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> Capture "narinfohash" NarInfoHash.NarInfoHash
-            :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate
-            :> Post '[JSON] NoContent,
-        createNar ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "nar"
-            :> StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ())
-            :> Post '[JSON] NoContent,
-        serveNarContent ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "serve"
-            :> Capture "storehash" Text
-            :> CaptureAll "filepath" Text
-            :> Summary "Serve a file from a given store path"
-            :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text] ByteStringStreaming.LazyByteStringStreaming),
-        createKey ::
-          route
-            :- CachixAuth
-            :> "cache"
-            :> Capture "name" Text
-            :> "key"
-            :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate
-            :> Post '[JSON] NoContent
-      }
+data BinaryCacheAPI route = BinaryCacheAPI
+  { -- https://cache.nixos.org/nix-cache-info
+    nixCacheInfo ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "nix-cache-info"
+        :> Get '[XNixCacheInfo, JSON] NixCacheInfo.NixCacheInfo,
+    -- Hydra: src/lib/Hydra/View/NARInfo.pm
+    narinfo ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> Capture "narinfohash" NarInfoHash.NarInfoHash
+        :> Get '[XNixNarInfo, JSON] (Headers '[Header "Cache-Control" Text] NarInfo.CachixNarInfo),
+    narinfoHead ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> Capture "narinfohash" NarInfoHash.NarInfoHash
+        :> Head,
+    -- Hydra: src/lib/Hydra/View/NixNAR.pm
+    nar ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "nar"
+        :> Capture "nar" NarFileName
+        :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ()),
+    -- cachix specific
+    getCache ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> Get '[JSON] BinaryCache.BinaryCache,
+    narinfoBulk ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "narinfo"
+        :> Summary "Given a list of store hashes, return a list of those that are missing"
+        :> ReqBody '[JSON] [Text]
+        :> Post '[JSON] [Text],
+    narURL ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "narurl"
+        :> Capture "nar" NarFileName
+        :> Get '[JSON] Text,
+    createNarinfo ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> Capture "narinfohash" NarInfoHash.NarInfoHash
+        :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate
+        :> Post '[JSON] NoContent,
+    createNar ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "nar"
+        :> StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ())
+        :> Post '[JSON] NoContent,
+    serveNarContent ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "serve"
+        :> Capture "storehash" Text
+        :> CaptureAll "filepath" Text
+        :> Summary "Serve a file from a given store path"
+        :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text, Header "Cache-Control" Text] ByteStringStreaming.LazyByteStringStreaming),
+    createKey ::
+      route
+        :- CachixAuth
+        :> "cache"
+        :> Capture "name" Text
+        :> "key"
+        :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate
+        :> Post '[JSON] NoContent
+  }
   deriving (Generic)
 
 type API = "api" :> "v1" :> ToServantApi BinaryCacheAPI
diff --git a/src/Cachix/API/Deploy.hs b/src/Cachix/API/Deploy.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/API/Deploy.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+
+module Cachix.API.Deploy where
+
+import Cachix.API (CachixAuth)
+import qualified Cachix.Types.ByteStringStreaming as ByteStringStreaming
+import qualified Cachix.Types.Deploy as Deploy
+import qualified Cachix.Types.DeployResponse as DeployResponse
+import Conduit (ConduitT, ResourceT)
+import qualified Data.UUID as UUID
+import Protolude
+import Servant.API
+import Servant.API.Generic
+
+data DeployAPI route = DeployAPI
+  { activate ::
+      route
+        :- CachixAuth
+        :> "deploy"
+        :> "activate"
+        :> ReqBody '[JSON] Deploy.Deploy
+        :> Post '[JSON] DeployResponse.DeployResponse
+  }
+  deriving (Generic)
+
+type API = "api" :> "v1" :> ToServantApi DeployAPI
+
+api :: Proxy API
+api = Proxy
diff --git a/src/Cachix/API/WebSocketSubprotocol.hs b/src/Cachix/API/WebSocketSubprotocol.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/API/WebSocketSubprotocol.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module Cachix.API.WebSocketSubprotocol where
+
+import qualified Control.Concurrent.Async as Async
+import qualified Control.Concurrent.Chan as Chan
+import qualified Data.Aeson as Aeson
+import Data.Time (UTCTime)
+import Data.UUID (UUID)
+import qualified Network.WebSockets as WS
+import Protolude
+
+data Message cmd = Message
+  { method :: Text,
+    command :: cmd,
+    agent :: Maybe UUID,
+    id :: UUID
+  }
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+data Cache = Cache
+  { cacheName :: Text,
+    publicKey :: Text,
+    isPublic :: Bool
+  }
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+data AgentInformation = AgentInformation
+  { cache :: Maybe Cache,
+    id :: UUID
+  }
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+data DeploymentDetails = DeploymentDetails
+  { storePath :: Text,
+    id :: UUID,
+    index :: Int64
+  }
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+data BackendCommand
+  = Deployment DeploymentDetails
+  | AgentRegistered AgentInformation
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+data AgentCommand
+  = DeploymentStarted {id :: UUID, time :: UTCTime}
+  | DeploymentFinished {id :: UUID, time :: UTCTime, hasSucceeded :: Bool}
+  deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)
+
+parseMessage :: Aeson.FromJSON cmd => ByteString -> Either Text (Message cmd)
+parseMessage body =
+  case Aeson.eitherDecodeStrict' body of
+    Left err -> Left $ toS err
+    Right message -> Right message
+
+sendMessage :: Aeson.ToJSON cmd => WS.Connection -> Message cmd -> IO ()
+sendMessage connection cmd =
+  WS.sendTextData connection $ Aeson.encode cmd
+
+-- TODO: use Async.replicateConcurrently
+recieveDataConcurrently :: WS.Connection -> (ByteString -> IO ()) -> IO ()
+recieveDataConcurrently connection m = do
+  channel <- Chan.newChan
+  Async.race_ (producer channel) (consumer channel)
+  where
+    producer channel = forever $ do
+      payload <- WS.receiveData connection
+      Chan.writeChan channel payload
+    consumer channel = forever $ do
+      payload <- Chan.readChan channel
+      m payload
+
+data Log = Log
+  { line :: Text,
+    time :: UTCTime
+  }
+  deriving (Generic, Show, Aeson.ToJSON, Aeson.FromJSON)
diff --git a/src/Cachix/Types/BinaryCache.hs b/src/Cachix/Types/BinaryCache.hs
--- a/src/Cachix/Types/BinaryCache.hs
+++ b/src/Cachix/Types/BinaryCache.hs
@@ -5,13 +5,12 @@
 import Data.Swagger (ToSchema)
 import Protolude
 
-data BinaryCache
-  = BinaryCache
-      { name :: Text,
-        uri :: Text,
-        isPublic :: Bool,
-        publicSigningKeys :: [Text],
-        githubUsername :: Text,
-        permission :: Permission
-      }
+data BinaryCache = BinaryCache
+  { name :: Text,
+    uri :: Text,
+    isPublic :: Bool,
+    publicSigningKeys :: [Text],
+    githubUsername :: Text,
+    permission :: Permission
+  }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
diff --git a/src/Cachix/Types/ContentTypes.hs b/src/Cachix/Types/ContentTypes.hs
--- a/src/Cachix/Types/ContentTypes.hs
+++ b/src/Cachix/Types/ContentTypes.hs
@@ -49,3 +49,9 @@
 
 instance MimeRender XNixNar ByteStringStreaming.LazyByteStringStreaming where
   mimeRender _ = coerce
+
+instance MimeRender PlainText ByteStringStreaming.ByteStringStreaming where
+  mimeRender _ = BSL.fromStrict . coerce
+
+instance MimeUnrender PlainText ByteStringStreaming.ByteStringStreaming where
+  mimeUnrender _ = Right . coerce . BSL.toStrict
diff --git a/src/Cachix/Types/Deploy.hs b/src/Cachix/Types/Deploy.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/Types/Deploy.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE DeriveAnyClass #-}
+
+module Cachix.Types.Deploy where
+
+import Data.Aeson
+  ( FromJSON,
+    ToJSON,
+  )
+import Data.HashMap.Strict
+import Data.Swagger (ToSchema)
+import Protolude
+
+newtype Deploy = Deploy
+  { agents :: HashMap Text Text
+  }
+  deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/DeployResponse.hs b/src/Cachix/Types/DeployResponse.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/Types/DeployResponse.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE DeriveAnyClass #-}
+
+module Cachix.Types.DeployResponse where
+
+import Data.Aeson
+  ( FromJSON,
+    ToJSON,
+  )
+import Data.HashMap.Strict
+import Data.Swagger (ToSchema)
+import Protolude
+
+newtype DeployResponse = DeployResponse
+  { agents :: HashMap Text Text
+  }
+  deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
diff --git a/src/Cachix/Types/NarFileName.hs b/src/Cachix/Types/NarFileName.hs
--- a/src/Cachix/Types/NarFileName.hs
+++ b/src/Cachix/Types/NarFileName.hs
@@ -9,11 +9,10 @@
 import Servant.API
 
 -- | <hash>.nar.<extension> file
-data NarFileName
-  = NarFileName
-      { contentHash :: Text,
-        extension :: Text
-      }
+data NarFileName = NarFileName
+  { contentHash :: Text,
+    extension :: Text
+  }
   deriving (Generic)
 
 instance FromHttpApiData NarFileName where
diff --git a/src/Cachix/Types/NarInfoCreate.hs b/src/Cachix/Types/NarInfoCreate.hs
--- a/src/Cachix/Types/NarInfoCreate.hs
+++ b/src/Cachix/Types/NarInfoCreate.hs
@@ -15,20 +15,19 @@
 -- TODO: get rid of c prefix
 
 -- | Client create type
-data NarInfoCreate
-  = NarInfoCreate
-      { -- | \$storePrefix / $storeHash - $storeSuffix
-        cStoreHash :: Text,
-        -- | \$storePrefix / $storeHash - $storeSuffix
-        cStoreSuffix :: Text,
-        cNarHash :: Text,
-        cNarSize :: Integer,
-        cFileHash :: Text,
-        cFileSize :: Integer,
-        cReferences :: [Text],
-        cDeriver :: Text,
-        cSig :: Maybe Text
-      }
+data NarInfoCreate = NarInfoCreate
+  { -- | \$storePrefix / $storeHash - $storeSuffix
+    cStoreHash :: Text,
+    -- | \$storePrefix / $storeHash - $storeSuffix
+    cStoreSuffix :: Text,
+    cNarHash :: Text,
+    cNarSize :: Integer,
+    cFileHash :: Text,
+    cFileSize :: Integer,
+    cReferences :: [Text],
+    cDeriver :: Text,
+    cSig :: Maybe Text
+  }
   deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
 
 data NarInfoInvalid
diff --git a/src/Cachix/Types/NixCacheInfo.hs b/src/Cachix/Types/NixCacheInfo.hs
--- a/src/Cachix/Types/NixCacheInfo.hs
+++ b/src/Cachix/Types/NixCacheInfo.hs
@@ -4,10 +4,9 @@
 import Data.Swagger (ToSchema)
 import Protolude
 
-data NixCacheInfo
-  = NixCacheInfo
-      { storeDir :: Text,
-        wantMassQuery :: Integer,
-        priority :: Integer
-      }
+data NixCacheInfo = NixCacheInfo
+  { storeDir :: Text,
+    wantMassQuery :: Integer,
+    priority :: Integer
+  }
   deriving (Generic, Show, FromJSON, ToJSON, ToSchema, NFData)
diff --git a/src/Cachix/Types/SigningKeyCreate.hs b/src/Cachix/Types/SigningKeyCreate.hs
--- a/src/Cachix/Types/SigningKeyCreate.hs
+++ b/src/Cachix/Types/SigningKeyCreate.hs
@@ -11,8 +11,7 @@
 import Protolude
 
 -- | Conveys that a signing secret key was created, by sharing the public key.
-newtype SigningKeyCreate
-  = SigningKeyCreate
-      { publicKey :: Text
-      }
+newtype SigningKeyCreate = SigningKeyCreate
+  { publicKey :: Text
+  }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
