diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h
index 92b221fdec151f6238550ef682ffe0f7203e0568..991909c4a9fb2a5aa2c94f860451b2c1ffea2844 100644
--- a/sys/include/net/gcoap.h
+++ b/sys/include/net/gcoap.h
@@ -484,20 +484,14 @@ void gcoap_register_listener(gcoap_listener_t *listener);
 
 /**
  * @brief   Initializes a CoAP request PDU on a buffer.
-
- * @warning After you use this function, you may not add Options with option
- * number less than COAP_OPT_URI_PATH. Otherwise, use the struct-based API
- * described with @link net_nanocoap nanocoap @endlink to initialize the
- * message. See the implementation of gcoap_req_init() itself as an example.
  *
  * @param[out] pdu      Request metadata
  * @param[out] buf      Buffer containing the PDU
  * @param[in] len       Length of the buffer
- * @param[in] code      Request code: GCOAP_[GET|POST|PUT|DELETE]
- * @param[in] path      Resource path, *must* start with '/'
+ * @param[in] code      Request code, one of COAP_METHOD_XXX
+ * @param[in] path      Resource path, may be NULL
  *
- * @pre @p path not `NULL`
- * @pre @p path must start with `/`
+ * @pre @p path must start with `/` if not NULL
  *
  * @return  0 on success
  * @return  < 0 on error
diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c
index 79c26dc87b485aeaee9e4299282090f25824611e..119a7aaa66b93fabfb94be50cbf751636f622da4 100644
--- a/sys/net/application_layer/gcoap/gcoap.c
+++ b/sys/net/application_layer/gcoap/gcoap.c
@@ -645,7 +645,7 @@ void gcoap_register_listener(gcoap_listener_t *listener)
 int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
                    unsigned code, const char *path)
 {
-    assert((path != NULL) && (path[0] == '/'));
+    assert((path == NULL) || (path[0] == '/'));
 
     pdu->hdr = (coap_hdr_t *)buf;
 
@@ -669,7 +669,9 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
 
     if (hdrlen > 0) {
         coap_pkt_init(pdu, buf, len - GCOAP_REQ_OPTIONS_BUF, hdrlen);
-        coap_opt_add_string(pdu, COAP_OPT_URI_PATH, path, '/');
+        if (path != NULL) {
+            coap_opt_add_string(pdu, COAP_OPT_URI_PATH, path, '/');
+        }
         return 0;
     }
     else {
diff --git a/tests/unittests/tests-gcoap/tests-gcoap.c b/tests/unittests/tests-gcoap/tests-gcoap.c
index d24517d8aadba716a63907985355e6c1978d72a6..a7f82e0a7b5f1a137a948925161444c4e13c3691 100644
--- a/tests/unittests/tests-gcoap/tests-gcoap.c
+++ b/tests/unittests/tests-gcoap/tests-gcoap.c
@@ -182,6 +182,32 @@ static void test_gcoap__client_get_query(void)
     TEST_ASSERT_EQUAL_STRING(&expected[0], &query[1]);
 }
 
+/*
+ * Builds on get_req test, to test use of NULL path with gcoap_req_init().
+ * Then separately add Uri-Path option later.
+ */
+static void test_gcoap__client_get_path_defer(void)
+{
+    uint8_t buf[GCOAP_PDU_BUF_SIZE];
+    coap_pkt_t pdu;
+    size_t len, optlen;
+    char path[] = "/time";
+
+    gcoap_req_init(&pdu, buf, GCOAP_PDU_BUF_SIZE, COAP_METHOD_GET, NULL);
+    coap_opt_add_uint(&pdu, COAP_OPT_OBSERVE, 0);
+    coap_opt_add_string(&pdu, COAP_OPT_URI_PATH, path, '/');
+    optlen = 6;
+
+    len = gcoap_finish(&pdu, 0, COAP_FORMAT_NONE);
+    TEST_ASSERT_EQUAL_INT(len, sizeof(coap_hdr_t) + GCOAP_TOKENLEN + optlen);
+
+    coap_parse(&pdu, buf, len);
+
+    char uri[NANOCOAP_URI_MAX] = {0};
+    coap_get_uri_path(&pdu, (uint8_t *)&uri[0]);
+    TEST_ASSERT_EQUAL_STRING(&path[0], &uri[0]);
+}
+
 /*
  * Helper for server_get tests below.
  * Request from libcoap example for gcoap_cli /cli/stats resource
@@ -346,6 +372,7 @@ Test *tests_gcoap_tests(void)
         new_TestFixture(test_gcoap__client_get_resp),
         new_TestFixture(test_gcoap__client_put_req),
         new_TestFixture(test_gcoap__client_get_query),
+        new_TestFixture(test_gcoap__client_get_path_defer),
         new_TestFixture(test_gcoap__server_get_req),
         new_TestFixture(test_gcoap__server_get_resp),
         new_TestFixture(test_gcoap__server_con_req),