diff --git a/grpc-etcd-client.cabal b/grpc-etcd-client.cabal
--- a/grpc-etcd-client.cabal
+++ b/grpc-etcd-client.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 1d9f9189c8c70a4bd052ee37baeeb5aa737942e526ae686d9b645e6816af3490
+-- hash: 3392648f92ab73a947ea1cebfa2c865ee727a9c4d122aca95a316bbbb2f3ea99
 
 name:           grpc-etcd-client
-version:        0.1.0.1
+version:        0.1.1.0
 synopsis:       gRPC client for etcd
 description:    Please see the README on GitHub at <https://github.com/lucasdicioccio/etcd-grpc#readme>
 category:       Distributed Computing
@@ -38,7 +38,7 @@
       base >=4.7 && <5
     , bytestring
     , data-default-class
-    , grpc-api-etcd ==0.1.0.0
+    , grpc-api-etcd ==0.1.0.1
     , http2-client
     , http2-client-grpc >=0.5 && <0.6
     , lens
diff --git a/src/Network/EtcdV3.hs b/src/Network/EtcdV3.hs
--- a/src/Network/EtcdV3.hs
+++ b/src/Network/EtcdV3.hs
@@ -17,11 +17,15 @@
     , keepAlive
     -- * Writing.
     , put
+    , delete
+    -- * Locking.
+    , AcquiredLock
+    , fromLockResponse
+    , lock
+    , unlock
     -- * re-exports
     , def
     , module Control.Lens
-    , module EtcdPB
-    , module EtcdRPC
     ) where
 
 import Control.Lens
@@ -33,8 +37,10 @@
 import Network.GRPC.Client
 import Network.GRPC.Client.Helpers
 import Network.Socket (HostName, PortNumber)
-import Proto.Etcd.Etcdserver.Etcdserverpb.Rpc as EtcdRPC
-import Proto.Etcd.Etcdserver.Etcdserverpb.Rpc_Fields as EtcdPB
+import qualified Proto.Etcd.Etcdserver.Etcdserverpb.Rpc as EtcdRPC
+import qualified Proto.Etcd.Etcdserver.Etcdserverpb.Rpc_Fields as EtcdPB
+import qualified Proto.Etcd.Etcdserver.Api.V3lock.V3lockpb.V3lock as LockRPC
+import qualified Proto.Etcd.Etcdserver.Api.V3lock.V3lockpb.V3lock_Fields as LockPB
 
 -- | EtcdClient configuration.
 etcdClientConfigSimple :: HostName -> PortNumber -> UseTlsOrNot -> GrpcClientConfig
@@ -67,9 +73,9 @@
   -- ^ Initialized gRPC client.
   -> KeyRange
   -- ^ Looked-up range.
-  -> EtcdQuery RangeResponse
+  -> EtcdQuery EtcdRPC.RangeResponse
 range grpc r = preview unaryOutput <$>
-    rawUnary (RPC :: RPC KV "range") grpc (def & key .~ k0 & rangeEnd .~ kend)
+    rawUnary (RPC :: RPC EtcdRPC.KV "range") grpc (def & EtcdPB.key .~ k0 & EtcdPB.rangeEnd .~ kend)
   where
     (k0, kend) = rangePairForRangeQuery r
 
@@ -84,8 +90,8 @@
 -- documentation to understand what you will miss out (e.g., whether the list
 -- is complete or not).
 rangeResponsePairs
-  :: Getting (Endo [(ByteString, ByteString)]) RangeResponse (ByteString, ByteString)
-rangeResponsePairs = kvs . traverse . to (\x -> (x ^. key, x ^. value))
+  :: Getting (Endo [(ByteString, ByteString)]) EtcdRPC.RangeResponse (ByteString, ByteString)
+rangeResponsePairs = EtcdPB.kvs . traverse . to (\x -> (x ^. EtcdPB.key, x ^. EtcdPB.value))
 
 -- | Internal helper for turning a 'KeyRange' into the start/end queries Etcd
 -- 'range' RPC needs.
@@ -103,9 +109,9 @@
   -- ^ Initialized gRPC client.
   -> Int64
   -- ^ TTL for the lease.
-  -> EtcdQuery LeaseGrantResponse
+  -> EtcdQuery EtcdRPC.LeaseGrantResponse
 grantLease grpc seconds =
-    preview unaryOutput <$> rawUnary (RPC :: RPC Lease "leaseGrant") grpc (def & ttl .~ seconds)
+    preview unaryOutput <$> rawUnary (RPC :: RPC EtcdRPC.Lease "leaseGrant") grpc (def & EtcdPB.ttl .~ seconds)
 
 -- | Opaque lease result.
 --
@@ -116,7 +122,7 @@
   show (GrantedLease n) = "(lease #" <> show n <> ")"
 
 -- | Constructor for 'GrantedLease'.
-fromLeaseGrantResponse :: LeaseGrantResponse -> GrantedLease
+fromLeaseGrantResponse :: EtcdRPC.LeaseGrantResponse -> GrantedLease
 fromLeaseGrantResponse r = GrantedLease $ r ^. EtcdPB.id
 
 -- | Keep a lease alive.
@@ -125,9 +131,9 @@
   -- ^ Initialized gRPC client.
   -> GrantedLease
   -- ^ A previously-granted lease.
-  -> EtcdQuery LeaseKeepAliveResponse
+  -> EtcdQuery EtcdRPC.LeaseKeepAliveResponse
 keepAlive grpc (GrantedLease leaseID) =
-    preview unaryOutput <$> rawUnary (RPC :: RPC Lease "leaseKeepAlive") grpc (def & EtcdPB.id .~ leaseID)
+    preview unaryOutput <$> rawUnary (RPC :: RPC EtcdRPC.Lease "leaseKeepAlive") grpc (def & EtcdPB.id .~ leaseID)
 
 -- | Put one value.
 put
@@ -140,8 +146,51 @@
   -- ^ Value.
   -> Maybe GrantedLease
   -- ^ Lease on the key.
-  -> EtcdQuery PutResponse
+  -> EtcdQuery EtcdRPC.PutResponse
 put grpc k v gl =
-    preview unaryOutput <$> rawUnary (RPC :: RPC KV "put") grpc (def & key .~ k & value .~ v & lease .~ l)
+    preview unaryOutput <$> rawUnary (RPC :: RPC EtcdRPC.KV "put") grpc (def & EtcdPB.key .~ k & EtcdPB.value .~ v & EtcdPB.lease .~ l)
   where
     l = maybe 0 _getGrantedLeaseId gl
+
+-- | Delete a range of values.
+delete
+  :: GrpcClient
+  -- ^ Initialized gRPC client.
+  -> KeyRange
+  -- ^ Deleted range.
+  -> EtcdQuery EtcdRPC.DeleteRangeResponse
+delete grpc r = preview unaryOutput <$>
+    rawUnary (RPC :: RPC EtcdRPC.KV "deleteRange") grpc (def & EtcdPB.key .~ k0 & EtcdPB.rangeEnd .~ kend)
+  where
+    (k0, kend) = rangePairForRangeQuery r
+
+-- | Opaque lock.
+--
+-- Show instance used for printing purposes only.
+newtype AcquiredLock = AcquiredLock { _getAcquiredLock :: ByteString }
+
+instance Show AcquiredLock where
+  show (AcquiredLock n) = "(lock #" <> show n <> ")"
+
+fromLockResponse :: LockRPC.LockResponse -> AcquiredLock
+fromLockResponse l = AcquiredLock $ l ^. LockPB.key
+
+lock
+  :: GrpcClient
+  -- ^ Initialized gRPC client.
+  -> ByteString
+  -- ^ Lock Name
+  -> GrantedLease
+  -- ^ Previously-granted lease that will bound the lifetime of the lock ownership.
+  -> EtcdQuery LockRPC.LockResponse
+lock grpc n (GrantedLease leaseID) = preview unaryOutput <$>
+    rawUnary (RPC :: RPC LockRPC.Lock "lock") grpc (def & LockPB.name .~ n & LockPB.lease .~ leaseID)
+
+unlock
+  :: GrpcClient
+  -- ^ Initialized gRPC client.
+  -> AcquiredLock
+  -- ^ Previously-acquired lock.
+  -> EtcdQuery LockRPC.UnlockResponse
+unlock grpc (AcquiredLock k) = preview unaryOutput <$>
+    rawUnary (RPC :: RPC LockRPC.Lock "unlock") grpc (def & LockPB.key .~ k)
