diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 2c39f4b6e68042cf60f6836e1c30eb1e91aa2fa3..993fc97adb6809082d0a9f20724bd4101da77889 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -199,6 +199,12 @@ typedef enum grpc_call_error {
 /** Mask of all valid flags. */
 #define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
 
+/* Initial metadata flags */
+/** Signal that the call is idempotent */
+#define GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST (0x00000010u)
+/** Mask of all valid flags */
+#define GRPC_INITIAL_METADATA_USED_MASK GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
+
 /** A single metadata element */
 typedef struct grpc_metadata {
   const char *key;
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 1aa27208c2e9725aebfad8b2ddfc18a29a9671c1..f08eb7e519ae50552b93676374ad85a004de8b95 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -112,7 +112,9 @@ static void hc_mutate_op(grpc_call_element *elem,
     /* Send : prefixed headers, which have to be before any application
        layer headers. */
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
-                                 GRPC_MDELEM_METHOD_POST);
+                                 op->idempotent_request
+                                     ? GRPC_MDELEM_METHOD_PUT
+                                     : GRPC_MDELEM_METHOD_POST);
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
                                  channeld->static_scheme);
     grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
@@ -242,7 +244,14 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
 }
 
 const grpc_channel_filter grpc_http_client_filter = {
-    hc_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    grpc_call_next_get_peer, "http-client"};
+    hc_start_transport_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "http-client"};
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 1b117aa6b8ca752f7987688c474d159c9d60f2f5..cf5c928d84ba4ab85aef51c8260109beef9caffa 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -909,7 +909,7 @@ static void set_cancelled_value(grpc_status_code status, void *dest) {
   *(int *)dest = (status != GRPC_STATUS_OK);
 }
 
-static int are_write_flags_valid(uint32_t flags) {
+static bool are_write_flags_valid(uint32_t flags) {
   /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
   const uint32_t allowed_write_positions =
       (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK);
@@ -917,6 +917,15 @@ static int are_write_flags_valid(uint32_t flags) {
   return !(flags & invalid_positions);
 }
 
+static bool are_initial_metadata_flags_valid(uint32_t flags, bool is_client) {
+  /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
+  uint32_t invalid_positions = ~GRPC_INITIAL_METADATA_USED_MASK;
+  if (!is_client) {
+    invalid_positions |= GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
+  }
+  return !(flags & invalid_positions);
+}
+
 static batch_control *allocate_batch_control(grpc_call *call) {
   size_t i;
   for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
@@ -1196,7 +1205,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
     switch (op->op) {
       case GRPC_OP_SEND_INITIAL_METADATA:
         /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
+        if (!are_initial_metadata_flags_valid(op->flags, call->is_client)) {
           error = GRPC_CALL_ERROR_INVALID_FLAGS;
           goto done_with_error;
         }
@@ -1220,6 +1229,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
         call->metadata_batch[0][0].deadline = call->send_deadline;
         stream_op.send_initial_metadata =
             &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
+        stream_op.idempotent_request =
+            (op->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) != 0;
         break;
       case GRPC_OP_SEND_MESSAGE:
         if (!are_write_flags_valid(op->flags)) {
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
index eeedae0619958d69db393971f744a0765a3c370e..fc01b89b1dadcb9cb69cb958cc696fabbe2c5c11 100644
--- a/src/core/transport/static_metadata.c
+++ b/src/core/transport/static_metadata.c
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
@@ -7,13 +6,13 @@
  * modification, are permitted provided that the following conditions are
  * met:
  *
- *     * Redistributions of source code must retain the above copyright
+ * * Redistributions of source code must retain the above copyright
  * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
+ * * Redistributions in binary form must reproduce the above
  * copyright notice, this list of conditions and the following disclaimer
  * in the documentation and/or other materials provided with the
  * distribution.
- *     * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google Inc. nor the names of its
  * contributors may be used to endorse or promote products derived from
  * this software without specific prior written permission.
  *
@@ -28,7 +27,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
  */
 
 /*
@@ -52,7 +50,7 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 3, 7, 5, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
     {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35,
@@ -60,30 +58,102 @@ const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
      30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33,
      42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53,
      46, 0,  46, 1,  46, 2,  50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35,
-     62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35,
-     70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35,
-     77, 35, 80, 3,  80, 4,  80, 5,  80, 6,  80, 7,  80, 8,  80, 9,  81, 35,
-     82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35};
+     62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 66, 71, 67, 79, 67, 80,
+     69, 35, 70, 35, 72, 35, 73, 35, 74, 35, 75, 35, 76, 41, 76, 51, 76, 52,
+     77, 35, 78, 35, 81, 3,  81, 4,  81, 5,  81, 6,  81, 7,  81, 8,  81, 9,
+     82, 35, 83, 84, 85, 35, 86, 35, 87, 35, 88, 35, 89, 35};
 
 const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
-    "0", "1", "2", "200", "204", "206", "304", "400", "404", "500", "accept",
-    "accept-charset", "accept-encoding", "accept-language", "accept-ranges",
-    "access-control-allow-origin", "age", "allow", "application/grpc",
-    ":authority", "authorization", "cache-control", "census-bin",
-    "census-binary-bin", "content-disposition", "content-encoding",
-    "content-language", "content-length", "content-location", "content-range",
-    "content-type", "cookie", "date", "deflate", "deflate,gzip", "", "etag",
-    "expect", "expires", "from", "GET", "grpc", "grpc-accept-encoding",
-    "grpc-encoding", "grpc-internal-encoding-request", "grpc-message",
-    "grpc-status", "grpc-timeout", "gzip", "gzip, deflate", "host", "http",
-    "https", "identity", "identity,deflate", "identity,deflate,gzip",
-    "identity,gzip", "if-match", "if-modified-since", "if-none-match",
-    "if-range", "if-unmodified-since", "last-modified", "link", "location",
-    "max-forwards", ":method", ":path", "POST", "proxy-authenticate",
-    "proxy-authorization", "range", "referer", "refresh", "retry-after",
-    ":scheme", "server", "set-cookie", "/", "/index.html", ":status",
-    "strict-transport-security", "te", "trailers", "transfer-encoding",
-    "user-agent", "vary", "via", "www-authenticate"};
+    "0",
+    "1",
+    "2",
+    "200",
+    "204",
+    "206",
+    "304",
+    "400",
+    "404",
+    "500",
+    "accept",
+    "accept-charset",
+    "accept-encoding",
+    "accept-language",
+    "accept-ranges",
+    "access-control-allow-origin",
+    "age",
+    "allow",
+    "application/grpc",
+    ":authority",
+    "authorization",
+    "cache-control",
+    "census-bin",
+    "census-binary-bin",
+    "content-disposition",
+    "content-encoding",
+    "content-language",
+    "content-length",
+    "content-location",
+    "content-range",
+    "content-type",
+    "cookie",
+    "date",
+    "deflate",
+    "deflate,gzip",
+    "",
+    "etag",
+    "expect",
+    "expires",
+    "from",
+    "GET",
+    "grpc",
+    "grpc-accept-encoding",
+    "grpc-encoding",
+    "grpc-internal-encoding-request",
+    "grpc-message",
+    "grpc-status",
+    "grpc-timeout",
+    "gzip",
+    "gzip, deflate",
+    "host",
+    "http",
+    "https",
+    "identity",
+    "identity,deflate",
+    "identity,deflate,gzip",
+    "identity,gzip",
+    "if-match",
+    "if-modified-since",
+    "if-none-match",
+    "if-range",
+    "if-unmodified-since",
+    "last-modified",
+    "link",
+    "location",
+    "max-forwards",
+    ":method",
+    ":path",
+    "POST",
+    "proxy-authenticate",
+    "proxy-authorization",
+    "PUT",
+    "range",
+    "referer",
+    "refresh",
+    "retry-after",
+    ":scheme",
+    "server",
+    "set-cookie",
+    "/",
+    "/index.html",
+    ":status",
+    "strict-transport-security",
+    "te",
+    "trailers",
+    "transfer-encoding",
+    "user-agent",
+    "vary",
+    "via",
+    "www-authenticate"};
 
 const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  29, 26, 30,
                                                          28, 32, 27, 31};
diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h
index ef72b802b51bbcbc35d0e888c886b2ee96efe955..b0e5b2fcdfa98959ca02e59b811ca2aa2ec738ef 100644
--- a/src/core/transport/static_metadata.h
+++ b/src/core/transport/static_metadata.h
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
@@ -7,13 +6,13 @@
  * modification, are permitted provided that the following conditions are
  * met:
  *
- *     * Redistributions of source code must retain the above copyright
+ * * Redistributions of source code must retain the above copyright
  * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
+ * * Redistributions in binary form must reproduce the above
  * copyright notice, this list of conditions and the following disclaimer
  * in the documentation and/or other materials provided with the
  * distribution.
- *     * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google Inc. nor the names of its
  * contributors may be used to endorse or promote products derived from
  * this software without specific prior written permission.
  *
@@ -28,7 +27,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
  */
 
 /*
@@ -48,7 +46,7 @@
 
 #include "src/core/transport/metadata.h"
 
-#define GRPC_STATIC_MDSTR_COUNT 89
+#define GRPC_STATIC_MDSTR_COUNT 90
 extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
 /* "0" */
 #define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
@@ -193,44 +191,46 @@ extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
 #define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69])
 /* "proxy-authorization" */
 #define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70])
+/* "PUT" */
+#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[71])
 /* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[72])
 /* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[73])
 /* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73])
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[74])
 /* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[75])
 /* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[76])
 /* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[77])
 /* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[78])
 /* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78])
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[79])
 /* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[80])
 /* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[81])
 /* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[82])
 /* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82])
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[83])
 /* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83])
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[84])
 /* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[85])
 /* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85])
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[86])
 /* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86])
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[87])
 /* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87])
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[88])
 /* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[89])
 
-#define GRPC_STATIC_MDELEM_COUNT 78
+#define GRPC_STATIC_MDELEM_COUNT 79
 extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
 /* "accept-charset": "" */
@@ -343,61 +343,63 @@ extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
 #define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49])
 /* ":method": "POST" */
 #define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50])
+/* ":method": "PUT" */
+#define GRPC_MDELEM_METHOD_PUT (&grpc_static_mdelem_table[51])
 /* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51])
+#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[52])
 /* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52])
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[53])
 /* "proxy-authenticate": "" */
-#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53])
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[54])
 /* "proxy-authorization": "" */
-#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54])
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[55])
 /* "range": "" */
-#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55])
+#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[56])
 /* "referer": "" */
-#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56])
+#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[57])
 /* "refresh": "" */
-#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57])
+#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[58])
 /* "retry-after": "" */
-#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58])
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[59])
 /* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59])
+#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[60])
 /* ":scheme": "http" */
-#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60])
+#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[61])
 /* ":scheme": "https" */
-#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61])
+#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[62])
 /* "server": "" */
-#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62])
+#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[63])
 /* "set-cookie": "" */
-#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63])
+#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[64])
 /* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64])
+#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[65])
 /* ":status": "204" */
-#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65])
+#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[66])
 /* ":status": "206" */
-#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66])
+#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[67])
 /* ":status": "304" */
-#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67])
+#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[68])
 /* ":status": "400" */
-#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68])
+#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[69])
 /* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69])
+#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[70])
 /* ":status": "500" */
-#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70])
+#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[71])
 /* "strict-transport-security": "" */
 #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
-  (&grpc_static_mdelem_table[71])
+  (&grpc_static_mdelem_table[72])
 /* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72])
+#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[73])
 /* "transfer-encoding": "" */
-#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73])
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[74])
 /* "user-agent": "" */
-#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74])
+#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[75])
 /* "vary": "" */
-#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75])
+#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[76])
 /* "via": "" */
-#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76])
+#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[77])
 /* "www-authenticate": "" */
-#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77])
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[78])
 
 extern const uint8_t
     grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index ed6e121c9cbb685e4b7e109a7f92110320f9c424..53f735ef23770b158e9d18b176b6ad1614e33f84 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -36,11 +36,11 @@
 
 #include <stddef.h>
 
+#include "src/core/channel/context.h"
 #include "src/core/iomgr/pollset.h"
 #include "src/core/iomgr/pollset_set.h"
-#include "src/core/transport/metadata_batch.h"
 #include "src/core/transport/byte_stream.h"
-#include "src/core/channel/context.h"
+#include "src/core/transport/metadata_batch.h"
 
 /* forward declarations */
 typedef struct grpc_transport grpc_transport;
@@ -81,8 +81,12 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount);
 /* Transport stream op: a set of operations to perform on a transport
    against a single stream */
 typedef struct grpc_transport_stream_op {
-  /** Send initial metadata to the peer, from the provided metadata batch. */
+  /** Send initial metadata to the peer, from the provided metadata batch.
+      idempotent_request MUST be set if this is non-null */
   grpc_metadata_batch *send_initial_metadata;
+  /** Iff send_initial_metadata != NULL, flags if this is an idempotent request
+      or not */
+  bool idempotent_request;
 
   /** Send trailing metadata to the peer, from the provided metadata batch. */
   grpc_metadata_batch *send_trailing_metadata;
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index e6ae00e61126dc8269305a8dd966e8e71c6d111d..a681804b3000bc1781f15633f4cedd2dd75dc93f 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -69,6 +69,7 @@ CONFIG = [
     (':scheme', 'grpc'),
     (':authority', ''),
     (':method', 'GET'),
+    (':method', 'PUT'),
     (':path', '/'),
     (':path', '/index.html'),
     (':status', '204'),
@@ -264,13 +265,13 @@ print >>C
 
 print >>H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems)
 print >>H, 'extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];'
-print >>H, 'extern gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];'
+print >>H, 'extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];'
 for i, elem in enumerate(all_elems):
   print >>H, '/* "%s": "%s" */' % elem
   print >>H, '#define %s (&grpc_static_mdelem_table[%d])' % (mangle(elem).upper(), i)
 print >>H
 print >>C, 'grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];'
-print >>C, 'gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {'
+print >>C, 'uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {'
 print >>C, '  %s' % ','.join('%d' % static_userdata.get(elem, 0) for elem in all_elems)
 print >>C, '};'
 print >>C
@@ -285,8 +286,8 @@ def md_idx(m):
     if m == m2:
       return i
 
-print >>H, 'extern const gpr_uint8 grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT*2];'
-print >>C, 'const gpr_uint8 grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT*2] = {'
+print >>H, 'extern const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT*2];'
+print >>C, 'const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT*2] = {'
 print >>C, ','.join('%d' % str_idx(x) for x in itertools.chain.from_iterable([a,b] for a, b in all_elems))
 print >>C, '};'
 print >>C
@@ -297,8 +298,8 @@ print >>C, '%s' % ',\n'.join('  "%s"' % s for s in all_strs)
 print >>C, '};'
 print >>C
 
-print >>H, 'extern const gpr_uint8 grpc_static_accept_encoding_metadata[%d];' % (1 << len(COMPRESSION_ALGORITHMS))
-print >>C, 'const gpr_uint8 grpc_static_accept_encoding_metadata[%d] = {' % (1 << len(COMPRESSION_ALGORITHMS))
+print >>H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (1 << len(COMPRESSION_ALGORITHMS))
+print >>C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % (1 << len(COMPRESSION_ALGORITHMS))
 print >>C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems)
 print >>C, '};'
 print >>C
@@ -309,4 +310,3 @@ print >>H, '#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H */'
 
 H.close()
 C.close()
-