diff --git a/sys/include/net/nanocoap.h b/sys/include/net/nanocoap.h
index b2ba50e2222ccd5aaa9c5015bc9f458a588febb5..ce481322b56b6dc1c1c333c385b8bcad7c8f87bb 100644
--- a/sys/include/net/nanocoap.h
+++ b/sys/include/net/nanocoap.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2016-17 Kaspar Schleiser <kaspar@schleiser.de>
  *               2018 Freie Universität Berlin
+ *               2018 Ken Bannister <kb2ma@runbox.com>
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -8,9 +9,102 @@
  */
 
 /**
- * @defgroup    net_nanocoap nanocoap small CoAP library
+ * @defgroup    net_nanocoap Nanocoap small CoAP library
  * @ingroup     net
- * @brief       Provides CoAP functionality optimized for minimal resource usage
+ * @brief       CoAP library optimized for minimal resource usage
+ *
+ * nanocoap provides a granular, low-level interface for writing CoAP messages
+ * via RIOT's sock networking API.
+ *
+ * ## Server Operation ##
+ *
+ * See the nanocoap_server example, which is built on the nanocoap_server()
+ * function. A server must define an array of coap_resource_t resources for
+ * which it responds. See the declarations of `coap_resources` and
+ * `coap_resources_numof`. The array contents must be ordered by the resource
+ * path, specifically the ASCII encoding of the path characters (digit and
+ * capital precede lower case). nanocoap provides the
+ * COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER entry for `/.well-known/core`.
+ *
+ * ### Handler functions ###
+ *
+ * For each resource, you must implement a ::coap_handler_t handler function.
+ * nanocoap provides functions to help implement the handler. If the handler
+ * is called via nanocoap_server(), the response buffer provided to the handler
+ * reuses the buffer for the request. So, your handler must read the request
+ * thoroughly before writing the response.
+ *
+ * To read the request, use the coap_get_xxx() functions to read the header and
+ * options. Use the coap_opt_get_xxx() functions to read an option generically
+ * by data type. If the pkt _payload_len_ attribute is a positive value, start
+ * to read it at the _payload_ pointer attribute.
+ *
+ * If a response does not require specific CoAP options, use
+ * coap_reply_simple(). If there is a payload, it writes a Content-Format
+ * option with the provided value.
+ *
+ * For a response with additional CoAP options, start by calling
+ * coap_build_reply(). Then choose either the minimal API or the struct-based
+ * API to write the rest of the response. See the instructions in the section
+ * _Write Options and Payload_ below.
+ *
+ * ## Client Operation ##
+ *
+ * Choose either the minimal API or the struct-based API to write a request.
+ * Follow the instructions in the section _Write Options and Payload_ below.
+ *
+ * To send the message and await the response, see nanocoap_request() as well
+ * as nanocoap_get(), which additionally copies the response payload to a user
+ * supplied buffer. Finally, read the response as described above in the server
+ * _Handler functions_ section for reading a request.
+ *
+ * ## Write Options and Payload ##
+ *
+ * For both server responses and client requests, CoAP uses an Option mechanism
+ * to encode message metadata that is not required for each message. For
+ * example, the resource URI path is required only for a request, and is encoded
+ * as the Uri-Path option.
+ *
+ * nanocoap provides two APIs for writing CoAP options:
+ *
+ * - **minimal API** requires only a reference to the buffer for the message.
+ * However, the caller must provide the last option number written as well as
+ * the buffer position.
+ *
+ * - **struct-based API** uses a coap_pkt_t struct to conveniently track each
+ * option as it is written and prepare for any payload.
+ *
+ * You must use one API exclusively for a given message. For either API, the
+ * caller must write options in order by option number (see "CoAP option
+ * numbers" in [CoAP defines](group__net__coap.html)).
+ *
+ * ### Minimal API ###
+ *
+ * Before starting, ensure the CoAP header has been initialized with
+ * coap_build_hdr(). For a response, coap_build_reply() includes a call to
+ * coap_build_hdr(). Use the returned length to track the next position in the
+ * buffer to write and remaining length.
+ *
+ * Next, use the coap_opt_put_xxx() and coap_put_xxx() functions to write each
+ * option. These functions require the position in the buffer to start writing,
+ * and return the number of bytes written.
+ *
+ * If there is a payload, append a payload marker (0xFF). Then write the
+ * payload to within the maximum length remaining in the buffer.
+ *
+ * ### Struct-based API ###
+ *
+ * As with the minimal API, first ensure the CoAP header has been initialized
+ * with coap_build_hdr(). Then use coap_pkt_init() to initialize the coap_pkt_t
+ * struct.
+ *
+ * Next, use the coap_opt_add_xxx() functions to write each option, like
+ * coap_opt_add_uint(). When all options have been added, call
+ * coap_opt_finish().
+ *
+ * Finally, write any message payload at the coap_pkt_t _payload_ pointer
+ * attribute. The _payload_len_ attribute provides the available length in the
+ * buffer. The option functions keep these values current as they are used.
  *
  * # Create a Block-wise Response (Block2)
  *