gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] 01/12: phase 1 of #6067: update exchange HTTPD to new A


From: gnunet
Subject: [taler-exchange] 01/12: phase 1 of #6067: update exchange HTTPD to new API style
Date: Sat, 29 Feb 2020 16:59:20 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

commit fb9324338d9580b520b3713bf973bfcd9c49b569
Author: Christian Grothoff <address@hidden>
AuthorDate: Wed Feb 26 17:00:41 2020 +0100

    phase 1 of #6067: update exchange HTTPD to new API style
---
 src/exchange/taler-exchange-httpd.c                | 534 +++++++++++++++------
 src/exchange/taler-exchange-httpd.h                |  74 ++-
 src/exchange/taler-exchange-httpd_deposit.c        |  40 +-
 src/exchange/taler-exchange-httpd_deposit.h        |  23 +-
 src/exchange/taler-exchange-httpd_keystate.c       |  17 +-
 src/exchange/taler-exchange-httpd_keystate.h       |  12 +-
 src/exchange/taler-exchange-httpd_mhd.c            |  52 +-
 src/exchange/taler-exchange-httpd_mhd.h            |  55 +--
 src/exchange/taler-exchange-httpd_recoup.c         |  40 +-
 src/exchange/taler-exchange-httpd_recoup.h         |  23 +-
 src/exchange/taler-exchange-httpd_refresh_link.c   |  42 +-
 src/exchange/taler-exchange-httpd_refresh_link.h   |  14 +-
 src/exchange/taler-exchange-httpd_refresh_melt.c   |  41 +-
 src/exchange/taler-exchange-httpd_refresh_melt.h   |  25 +-
 src/exchange/taler-exchange-httpd_refresh_reveal.c |  57 ++-
 src/exchange/taler-exchange-httpd_refresh_reveal.h |  23 +-
 src/exchange/taler-exchange-httpd_refund.c         |  39 +-
 src/exchange/taler-exchange-httpd_refund.h         |  23 +-
 src/exchange/taler-exchange-httpd_reserve_status.c |  43 +-
 src/exchange/taler-exchange-httpd_reserve_status.h |  21 +-
 .../taler-exchange-httpd_reserve_withdraw.c        |  52 +-
 .../taler-exchange-httpd_reserve_withdraw.h        |  28 +-
 src/exchange/taler-exchange-httpd_terms.c          |  28 +-
 src/exchange/taler-exchange-httpd_terms.h          |  21 +-
 .../taler-exchange-httpd_track_transaction.c       | 108 +++--
 .../taler-exchange-httpd_track_transaction.h       |  14 +-
 src/exchange/taler-exchange-httpd_track_transfer.c |  41 +-
 src/exchange/taler-exchange-httpd_track_transfer.h |  13 +-
 src/exchange/taler-exchange-httpd_validation.c     |   1 -
 src/exchange/taler-exchange-httpd_wire.c           |  14 +-
 src/exchange/taler-exchange-httpd_wire.h           |  12 +-
 src/include/taler_error_codes.h                    |  70 +++
 32 files changed, 871 insertions(+), 729 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 6f021d72..288b4578 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016, 2019 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -147,6 +147,92 @@ static unsigned long long req_count;
 static unsigned long long req_max;
 
 
+/**
+ * Handle a "/coins/$COIN_PUB/$OP" POST request.  Parses the "coin_pub"
+ * EdDSA key of the coin and demultiplexes based on $OP.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param root uploaded JSON data
+ * @param args array of additional options (first must be the
+ *         reserve public key, the second one should be "withdraw")
+ * @return MHD result code
+ */
+static int
+handle_post_coins (const struct TEH_RequestHandler *rh,
+                   struct MHD_Connection *connection,
+                   const json_t *root,
+                   const char *const args[2])
+{
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+  static const struct
+  {
+    /**
+     * Name of the operation (args[1])
+     */
+    const char *op;
+
+    /**
+     * Function to call to perform the operation.
+     *
+     * @param connection the MHD connection to handle
+     * @param coin_pub the public key of the coin
+     * @param root uploaded JSON data
+     * @return MHD result code
+     *///
+    int
+    (*handler)(struct MHD_Connection *connection,
+               const struct TALER_CoinSpendPublicKeyP *coin_pub,
+               const json_t *root);
+  } h[] = {
+    {
+      .op = "deposit",
+      .handler = &TEH_DEPOSIT_handler_deposit
+    },
+    {
+      .op = "melt",
+      .handler = &TEH_REFRESH_handler_melt
+    },
+    {
+      .op = "recoup",
+      .handler = &TEH_RECOUP_handler_recoup
+    },
+    {
+      .op = "refund",
+      .handler = &TEH_REFUND_handler_refund
+    },
+    {
+      .op = NULL,
+      .handler = NULL
+    },
+  };
+
+  (void) rh;
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &coin_pub,
+                                     sizeof (coin_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_COINS_INVALID_COIN_PUB,
+                                       "coin public key malformed");
+  }
+  for (unsigned int i = 0; NULL != h[i].op; i++)
+    if (0 == strcmp (h[i].op,
+                     args[1]))
+      return h[i].handler (connection,
+                           &coin_pub,
+                           root);
+  return TALER_MHD_reply_with_error (connection,
+                                     MHD_HTTP_NOT_FOUND,
+                                     TALER_EC_OPERATION_INVALID,
+                                     "requested operation on coin unknown");
+}
+
+
 /**
  * Function called whenever MHD is done with a request.  If the
  * request was a POST, we may have stored a `struct Buffer *` in the
@@ -205,6 +291,120 @@ is_valid_correlation_id (const char *correlation_id)
 }
 
 
+/**
+ * We found @a rh responsible for handling a request. Parse the
+ * @a upload_data (if applicable) and the @a url and call the
+ * handler.
+ *
+ * @param rh request handler to call
+ * @param connection connection being handled
+ * @param url rest of the URL to parse
+ * @param inner_cls closure for the handler, if needed
+ * @param upload_data upload data to parse (if available)
+ * @param upload_data_size[in,out] number of bytes in @a upload_data
+ * @return MHD result code
+ */
+static int
+proceed_with_handler (const struct TEH_RequestHandler *rh,
+                      struct MHD_Connection *connection,
+                      const char *url,
+                      void **inner_cls,
+                      const char *upload_data,
+                      size_t *upload_data_size)
+{
+  const char *args[rh->nargs + 1];
+  size_t ulen = strlen (url) + 1;
+  json_t *root;
+  int ret;
+
+  /* We do check for "ulen" here, because we'll later stack-allocate a buffer
+     of that size and don't want to enable malicious clients to cause us
+     huge stack allocations. */
+  if (ulen > 512)
+  {
+    /* 512 is simply "big enough", as it is bigger than "6 * 54",
+       which is the longest URL format we ever get (for
+       /deposits/).  The value should be adjusted if we ever define protocol
+       endpoints with plausibly longer inputs.  */
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_URI_TOO_LONG,
+                                       TALER_EC_URI_TOO_LONG,
+                                       "The URI given is too long");
+  }
+
+  /* All POST endpoints come with a body in JSON format. So we parse
+     the JSON here. */
+  if (0 == strcasecmp (rh->method,
+                       MHD_HTTP_METHOD_POST))
+  {
+    int res;
+
+    res = TALER_MHD_parse_post_json (connection,
+                                     inner_cls,
+                                     upload_data,
+                                     upload_data_size,
+                                     &root);
+    if (GNUNET_SYSERR == res)
+      return MHD_NO;
+    if ( (GNUNET_NO == res) || (NULL == root) )
+      return MHD_YES;
+  }
+
+  {
+    char d[ulen];
+
+    /* Parse command-line arguments, if applicable */
+    if (rh->nargs > 0)
+    {
+      unsigned int i;
+
+      /* make a copy of 'url' because 'strtok()' will modify */
+      memcpy (d,
+              url,
+              ulen);
+      i = 0;
+      args[i++] = strtok (d, "/");
+      while ( (NULL != args[i - 1]) &&
+              (i < rh->nargs) )
+        args[i++] = strtok (NULL, "/");
+      /* make sure above loop ran nicely until completion, and also
+         that there is no excess data in 'd' afterwards */
+      if ( (i != rh->nargs) ||
+           (NULL == args[i - 1]) ||
+           (NULL != strtok (NULL, "/")) )
+      {
+        GNUNET_break_op (0);
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_NOT_FOUND,
+                                           TALER_EC_WRONG_NUMBER_OF_SEGMENTS,
+                                           "Number of segments does not 
match");
+      }
+    }
+
+    /* just to be safe(r), we always terminate the array with a NULL
+       (which handlers should not read, but at least if they do, they'll
+       crash pretty reliably... */
+    args[rh->nargs] = NULL;
+
+    /* Above logic ensures that 'root' is exactly non-NULL for POST operations 
*/
+    if (NULL != root)
+      ret = rh->handler.post (rh,
+                              connection,
+                              root,
+                              args);
+    else /* and we only have "POST" or "GET" in the API for at this point
+            (OPTIONS/HEAD are taken care of earlier) */
+      ret = rh->handler.get (rh,
+                             connection,
+                             args);
+  }
+  if (NULL != root)
+    json_decref (root);
+  return ret;
+}
+
+
 /**
  * Handle incoming HTTP request.
  *
@@ -229,134 +429,111 @@ handle_mhd_request (void *cls,
                     void **con_cls)
 {
   static struct TEH_RequestHandler handlers[] = {
-    /* Landing page, tell humans to go away. */
-    { "/", MHD_HTTP_METHOD_GET, "text/plain",
-      "Hello, I'm the Taler exchange. This HTTP server is not for humans.\n", 
0,
-      &TEH_MHD_handler_static_response, MHD_HTTP_OK },
     /* /robots.txt: disallow everything */
-    { "/robots.txt", MHD_HTTP_METHOD_GET, "text/plain",
-      "User-agent: *\nDisallow: /\n", 0,
-      &TEH_MHD_handler_static_response, MHD_HTTP_OK },
+    {
+      .url = "robots.txt",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_MHD_handler_static_response,
+      .mime_type = "text/plain",
+      .data = "User-agent: *\nDisallow: /\n",
+      .response_code = MHD_HTTP_OK
+    },
+    /* Landing page, tell humans to go away. */
+    {
+      .url = "",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = TEH_MHD_handler_static_response,
+      .mime_type = "text/plain",
+      .data =
+        "Hello, I'm the Taler exchange. This HTTP server is not for humans.\n",
+      .response_code = MHD_HTTP_OK
+    },
     /* AGPL licensing page, redirect to source. As per the AGPL-license,
        every deployment is required to offer the user a download of the
        source. We make this easy by including a redirect to the source
        here. */
-    { "/agpl", MHD_HTTP_METHOD_GET, "text/plain",
-      NULL, 0,
-      &TEH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND },
+    {
+      .url = "agpl",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_MHD_handler_agpl_redirect
+    },
     /* Terms of service */
-    { "/terms", MHD_HTTP_METHOD_GET, NULL,
-      NULL, 0,
-      &TEH_handler_terms, MHD_HTTP_OK },
+    {
+      .url = "terms",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_handler_terms
+    },
     /* Privacy policy */
-    { "/privacy", MHD_HTTP_METHOD_GET, NULL,
-      NULL, 0,
-      &TEH_handler_privacy, MHD_HTTP_OK },
+    {
+      .url = "privacy",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_handler_privacy
+    },
     /* Return key material and fundamental properties for this exchange */
-    { "/keys", MHD_HTTP_METHOD_GET, "application/json",
-      NULL, 0,
-      &TEH_KS_handler_keys, MHD_HTTP_OK },
-    { "/keys", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
+    {
+      .url = "/keys",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_KS_handler_keys,
+    },
     /* Requests for wiring information */
-    { "/wire", MHD_HTTP_METHOD_GET, "application/json",
-      NULL, 0,
-      &TEH_WIRE_handler_wire, MHD_HTTP_OK },
-    { "/wire", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
+    {
+      .url = "wire",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_WIRE_handler_wire
+    },
     /* Withdrawing coins / interaction with reserves */
-    { "/reserve/status", MHD_HTTP_METHOD_GET, "application/json",
-      NULL, 0,
-      &TEH_RESERVE_handler_reserve_status, MHD_HTTP_OK },
-    { "/reserve/status", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/reserve/withdraw", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_RESERVE_handler_reserve_withdraw, MHD_HTTP_OK },
-    { "/reserve/withdraw", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    /* Depositing coins */
-    { "/deposit", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_DEPOSIT_handler_deposit, MHD_HTTP_OK },
-    { "/deposit", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    /* Refunding coins */
-    { "/refund", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_REFUND_handler_refund, MHD_HTTP_OK },
-    { "/refund", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    /* Dealing with change */
-    { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_REFRESH_handler_refresh_melt, MHD_HTTP_OK },
-    { "/refresh/melt", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
-    { "/refresh/reveal", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK },
-    { "/refresh/reveal", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json",
-      NULL, 0,
-      &TEH_REFRESH_handler_refresh_link, MHD_HTTP_OK },
-    { "/refresh/link", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/track/transfer", MHD_HTTP_METHOD_GET, "application/json",
-      NULL, 0,
-      &TEH_TRACKING_handler_track_transfer, MHD_HTTP_OK },
-    { "/track/transfer", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-    { "/track/transaction", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_TRACKING_handler_track_transaction, MHD_HTTP_OK },
-    { "/track/transaction", NULL, "text/plain",
-      "Only POST is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { "/recoup", MHD_HTTP_METHOD_POST, "application/json",
-      NULL, 0,
-      &TEH_RECOUP_handler_recoup, MHD_HTTP_OK },
-    { "/refresh/link", NULL, "text/plain",
-      "Only GET is allowed", 0,
-      &TEH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
-    { NULL, NULL, NULL, NULL, 0, NULL, 0 }
-  };
-  static struct TEH_RequestHandler h404 = {
-    "", NULL, "text/html",
-    "<html><title>404: not found</title></html>", 0,
-    &TEH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
+    {
+      .url = "reserves",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_RESERVE_handler_reserve_status,
+      .nargs = 1
+    },
+    {
+      .url = "reserves",
+      .method = MHD_HTTP_METHOD_POST,
+      .handler.post = &TEH_RESERVE_handler_reserve_withdraw,
+      .nargs = 2
+    },
+    /* coins */
+    {
+      .url = "coins",
+      .method = MHD_HTTP_METHOD_POST,
+      .handler.post = &handle_post_coins,
+      .nargs = 2
+    },
+    {
+      .url = "coins",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = TEH_REFRESH_handler_link,
+      .nargs = 2,
+    },
+    /* refreshing */
+    {
+      .url = "refreshes",
+      .method = MHD_HTTP_METHOD_POST,
+      .handler.post = &TEH_REFRESH_handler_reveal,
+      .nargs = 2
+    },
+    /* tracking transfers */
+    {
+      .url = "transfers",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_TRACKING_handler_track_transfer,
+      .nargs = 1
+    },
+    /* tracking deposits */
+    {
+      .url = "deposits",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_TRACKING_handler_track_transaction,
+      .nargs = 4
+    },
+    /* mark end of list */
+    {
+      .url = NULL
+    }
   };
   struct ExchangeHttpRequestClosure *ecls = *con_cls;
-  int ret;
   void **inner_cls;
   struct GNUNET_AsyncScopeSave old_scope;
   const char *correlation_id = NULL;
@@ -367,7 +544,8 @@ handle_mhd_request (void *cls,
   {
     unsigned long long cnt;
 
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Handling new request\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Handling new request\n");
     cnt = __sync_add_and_fetch (&req_count, 1LLU);
     if (req_max == cnt)
     {
@@ -395,7 +573,8 @@ handle_mhd_request (void *cls,
   }
 
   inner_cls = &ecls->opaque_post_parsing_context;
-  GNUNET_async_scope_enter (&ecls->async_scope_id, &old_scope);
+  GNUNET_async_scope_enter (&ecls->async_scope_id,
+                            &old_scope);
   if (NULL != correlation_id)
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Handling request (%s) for URL '%s', correlation_id=%s\n",
@@ -410,55 +589,100 @@ handle_mhd_request (void *cls,
   /* on repeated requests, check our cache first */
   if (NULL != ecls->rh)
   {
-    ret = ecls->rh->handler (ecls->rh,
-                             connection,
-                             inner_cls,
-                             upload_data,
-                             upload_data_size);
+    int ret;
+
+    ret = proceed_with_handler (ecls->rh,
+                                connection,
+                                url,
+                                inner_cls,
+                                upload_data,
+                                upload_data_size);
     GNUNET_async_scope_restore (&old_scope);
     return ret;
   }
+
   if (0 == strcasecmp (method,
                        MHD_HTTP_METHOD_HEAD))
-    method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the 
rest */
-  for (unsigned int i = 0; NULL != handlers[i].url; i++)
-  {
-    struct TEH_RequestHandler *rh = &handlers[i];
-
-    if (0 != strcmp (url, rh->url))
-      continue;
+    method = MHD_HTTP_METHOD_GET;   /* treat HEAD as GET here, MHD will do the 
rest */
 
-    /* The URL is a match!  What we now do depends on the method. */
-    if (0 == strcasecmp (method, MHD_HTTP_METHOD_OPTIONS))
+  /* parse first part of URL */
+  {
+    int found = GNUNET_NO;
+    size_t tok_size;
+    const char *tok;
+    const char *rest;
+
+    if ('\0' == url[0])
+      /* strange, should start with '/', treat as just "/" */
+      url = "/";
+    tok = url + 1;
+    rest = strchr (tok, '/');
+    if (NULL == rest)
+    {
+      tok_size = 0;
+    }
+    else
+    {
+      tok_size = rest - tok;
+      rest++; /* skip over '/' */
+    }
+    for (unsigned int i = 0; NULL != handlers[i].url; i++)
     {
-      GNUNET_async_scope_restore (&old_scope);
-      return TALER_MHD_reply_cors_preflight (connection);
+      struct TEH_RequestHandler *rh = &handlers[i];
+
+      if (0 != strncmp (tok,
+                        rh->url,
+                        tok_size))
+        continue;
+      found = GNUNET_YES;
+      /* The URL is a match!  What we now do depends on the method. */
+      if (0 == strcasecmp (method, MHD_HTTP_METHOD_OPTIONS))
+      {
+        GNUNET_async_scope_restore (&old_scope);
+        return TALER_MHD_reply_cors_preflight (connection);
+      }
+      GNUNET_assert (NULL != rh->method);
+      if (0 == strcasecmp (method,
+                           rh->method))
+      {
+        int ret;
+
+        /* cache to avoid the loop next time */
+        ecls->rh = rh;
+        /* run handler */
+        ret = proceed_with_handler (rh,
+                                    connection,
+                                    url,
+                                    inner_cls,
+                                    upload_data,
+                                    upload_data_size);
+        GNUNET_async_scope_restore (&old_scope);
+        return ret;
+      }
     }
 
-    if ( (NULL == rh->method) ||
-         (0 == strcasecmp (method,
-                           rh->method)) )
+    if (GNUNET_YES == found)
     {
-      /* cache to avoid the loop next time */
-      ecls->rh = rh;
-      /* run handler */
-      ret = rh->handler (rh,
-                         connection,
-                         inner_cls,
-                         upload_data,
-                         upload_data_size);
-      GNUNET_async_scope_restore (&old_scope);
-      return ret;
+      /* we found a matching address, but the method is wrong */
+      GNUNET_break_op (0);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_METHOD_NOT_ALLOWED,
+                                         TALER_EC_METHOD_INVALID,
+                                         "The HTTP method used is invalid for 
this URL");
     }
   }
+
   /* No handler matches, generate not found */
-  ret = TEH_MHD_handler_static_response (&h404,
-                                         connection,
-                                         inner_cls,
-                                         upload_data,
-                                         upload_data_size);
-  GNUNET_async_scope_restore (&old_scope);
-  return ret;
+  {
+    int ret;
+
+    ret = TALER_MHD_reply_with_error (connection,
+                                      MHD_HTTP_NOT_FOUND,
+                                      TALER_EC_ENDPOINT_UNKNOWN,
+                                      "No handler found for the given URL");
+    GNUNET_async_scope_restore (&old_scope);
+    return ret;
+  }
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd.h 
b/src/exchange/taler-exchange-httpd.h
index 38c611c6..8489d179 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -24,6 +24,8 @@
 #define TALER_EXCHANGE_HTTPD_H
 
 #include <microhttpd.h>
+#include "taler_json_lib.h"
+#include "taler_crypto_lib.h"
 
 
 /**
@@ -65,51 +67,77 @@ struct TEH_RequestHandler
 {
 
   /**
-   * URL the handler is for.
+   * URL the handler is for (first part only).
    */
   const char *url;
 
   /**
-   * Method the handler is for, NULL for "all".
+   * Method the handler is for.
    */
   const char *method;
 
+  /**
+   * Callbacks for handling of the request. Which one is used
+   * depends on @e method.
+   */
+  union
+  {
+    /**
+     * Function to call to handle a GET requests (and those
+     * with @e method NULL).
+     *
+     * @param rh this struct
+     * @param mime_type the @e mime_type for the reply (hint, can be NULL)
+     * @param connection the MHD connection to handle
+     * @param args array of arguments, needs to be of length @e args_expected
+     * @return MHD result code
+     */
+    int (*get)(const struct TEH_RequestHandler *rh,
+               struct MHD_Connection *connection,
+               const char *const args[]);
+
+
+    /**
+     * Function to call to handle a POST request.
+     *
+     * @param rh this struct
+     * @param mime_type the @e mime_type for the reply (hint, can be NULL)
+     * @param connection the MHD connection to handle
+     * @param json uploaded JSON data
+     * @param args array of arguments, needs to be of length @e args_expected
+     * @return MHD result code
+     */
+    int (*post)(const struct TEH_RequestHandler *rh,
+                struct MHD_Connection *connection,
+                const json_t *root,
+                const char *const args[]);
+
+  } handler;
+
+  /**
+   * Number of arguments this handler expects in the @a args array.
+   */
+  unsigned int nargs;
+
   /**
    * Mime type to use in reply (hint, can be NULL).
    */
   const char *mime_type;
 
   /**
-   * Raw data for the @e handler
+   * Raw data for the @e handler, can be NULL for none provided.
    */
   const void *data;
 
   /**
-   * Number of bytes in @e data, 0 for 0-terminated.
+   * Number of bytes in @e data, 0 for data is 0-terminated (!).
    */
   size_t data_size;
 
   /**
-   * Function to call to handle the request.
-   *
-   * @param rh this struct
-   * @param mime_type the @e mime_type for the reply (hint, can be NULL)
-   * @param connection the MHD connection to handle
-   * @param[in,out] connection_cls the connection's closure (can be updated)
-   * @param upload_data upload data
-   * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
-   * @return MHD result code
-   */
-  int (*handler)(struct TEH_RequestHandler *rh,
-                 struct MHD_Connection *connection,
-                 void **connection_cls,
-                 const char *upload_data,
-                 size_t *upload_data_size);
-
-  /**
-   * Default response code.
+   * Default response code. 0 for none provided.
    */
-  int response_code;
+  unsigned int response_code;
 };
 
 
diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 49b9cc2f..da89ff47 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -381,27 +381,22 @@ check_timestamp_current (struct GNUNET_TIME_Absolute ts)
 
 
 /**
- * Handle a "/deposit" request.  Parses the JSON, and, if successful,
- * passes the JSON data to #verify_and_execute_deposit() to further
- * check the details of the operation specified.  If everything checks
+ * Handle a "/coins/$COIN_PUB/deposit" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_deposit() to
+ * further check the details of the operation specified.  If everything checks
  * out, this will ultimately lead to the "/deposit" being executed, or
  * rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
-                             struct MHD_Connection *connection,
-                             void **connection_cls,
-                             const char *upload_data,
-                             size_t *upload_data_size)
+TEH_DEPOSIT_handler_deposit (struct MHD_Connection *connection,
+                             const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                             const json_t *root)
 {
-  json_t *json;
   int res;
   json_t *wire;
   enum TALER_ErrorCode ec;
@@ -415,7 +410,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
                                  &deposit.coin.denom_pub_hash),
     TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
-    GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub),
     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &deposit.merchant_pub),
     GNUNET_JSON_spec_fixed_auto ("h_contract_terms", 
&deposit.h_contract_terms),
     GNUNET_JSON_spec_fixed_auto ("h_wire", &deposit.h_wire),
@@ -428,27 +422,13 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler 
*rh,
     GNUNET_JSON_spec_end ()
   };
 
-  (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &json);
-  if (GNUNET_SYSERR == res)
-  {
-    GNUNET_break (0);
-    return MHD_NO;
-  }
-  if ( (GNUNET_NO == res) ||
-       (NULL == json) )
-    return MHD_YES;
   memset (&deposit,
           0,
           sizeof (deposit));
+  deposit.coin.coin_pub = *coin_pub;
   res = TALER_MHD_parse_json_data (connection,
-                                   json,
+                                   root,
                                    spec);
-  json_decref (json);
   if (GNUNET_SYSERR == res)
   {
     GNUNET_break (0);
diff --git a/src/exchange/taler-exchange-httpd_deposit.h 
b/src/exchange/taler-exchange-httpd_deposit.h
index ed1f87d5..23c46c28 100644
--- a/src/exchange/taler-exchange-httpd_deposit.h
+++ b/src/exchange/taler-exchange-httpd_deposit.h
@@ -29,22 +29,21 @@
 
 
 /**
- * Handle a "/deposit" request.  Parses the JSON, and, if successful,
- * checks the signatures.  If everything checks out, this will
- * ultimately lead to the "/deposit" being executed, or rejected.
+ * Handle a "/coins/$COIN_PUB/deposit" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_deposit() to
+ * further check the details of the operation specified.  If everything checks
+ * out, this will ultimately lead to the "/deposit" being executed, or
+ * rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
-                             struct MHD_Connection *connection,
-                             void **connection_cls,
-                             const char *upload_data,
-                             size_t *upload_data_size);
+TEH_DEPOSIT_handler_deposit (struct MHD_Connection *connection,
+                             const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                             const json_t *root);
+
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_keystate.c 
b/src/exchange/taler-exchange-httpd_keystate.c
index 27f22925..f0ab2a0d 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -2381,17 +2381,13 @@ krd_search_comparator (const void *key,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
+TEH_KS_handler_keys (const struct TEH_RequestHandler *rh,
                      struct MHD_Connection *connection,
-                     void **connection_cls,
-                     const char *upload_data,
-                     size_t *upload_data_size)
+                     const char *const args[])
 {
   int ret;
   const char *have_cherrypick;
@@ -2400,9 +2396,8 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
   struct GNUNET_TIME_Absolute now;
   const struct KeysResponseData *krd;
 
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
+  (void) rh;
+  (void) args;
   have_cherrypick = MHD_lookup_connection_value (connection,
                                                  MHD_GET_ARGUMENT_KIND,
                                                  "last_issue_date");
@@ -2493,7 +2488,7 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
                                          "no key response found");
     }
     ret = MHD_queue_response (connection,
-                              rh->response_code,
+                              MHD_HTTP_OK,
                               (MHD_YES == TALER_MHD_can_compress (connection))
                               ? krd->response_compressed
                               : krd->response_uncompressed);
diff --git a/src/exchange/taler-exchange-httpd_keystate.h 
b/src/exchange/taler-exchange-httpd_keystate.h
index ebcefa08..a6906096 100644
--- a/src/exchange/taler-exchange-httpd_keystate.h
+++ b/src/exchange/taler-exchange-httpd_keystate.h
@@ -188,17 +188,13 @@ TEH_KS_sign (const struct 
GNUNET_CRYPTO_EccSignaturePurpose *purpose,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
-  */
+ */
 int
-TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
+TEH_KS_handler_keys (const struct TEH_RequestHandler *rh,
                      struct MHD_Connection *connection,
-                     void **connection_cls,
-                     const char *upload_data,
-                     size_t *upload_data_size);
+                     const char *const args[]);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_mhd.c 
b/src/exchange/taler-exchange-httpd_mhd.c
index 0f2ce033..0d59fad1 100644
--- a/src/exchange/taler-exchange-httpd_mhd.c
+++ b/src/exchange/taler-exchange-httpd_mhd.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -39,27 +39,23 @@
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_static_response (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_static_response (const struct TEH_RequestHandler *rh,
                                  struct MHD_Connection *connection,
-                                 void **connection_cls,
-                                 const char *upload_data,
-                                 size_t *upload_data_size)
+                                 const char *const args[])
 {
   struct MHD_Response *response;
   int ret;
+  size_t dlen;
 
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
-  if (0 == rh->data_size)
-    rh->data_size = strlen ((const char *) rh->data);
-  response = MHD_create_response_from_buffer (rh->data_size,
+  (void) args;
+  dlen = (0 == rh->data_size)
+         ? strlen ((const char *) rh->data)
+         : rh->data_size;
+  response = MHD_create_response_from_buffer (dlen,
                                               (void *) rh->data,
                                               MHD_RESPMEM_PERSISTENT);
   if (NULL == response)
@@ -86,22 +82,16 @@ TEH_MHD_handler_static_response (struct TEH_RequestHandler 
*rh,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_agpl_redirect (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_agpl_redirect (const struct TEH_RequestHandler *rh,
                                struct MHD_Connection *connection,
-                               void **connection_cls,
-                               const char *upload_data,
-                               size_t *upload_data_size)
+                               const char *const args[])
 {
   (void) rh;
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
+  (void) args;
   return TALER_MHD_reply_agpl (connection,
                                "http://www.git.taler.net/?p=exchange.git";);
 }
@@ -113,21 +103,15 @@ TEH_MHD_handler_agpl_redirect (struct TEH_RequestHandler 
*rh,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_send_json_pack_error (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_send_json_pack_error (const struct TEH_RequestHandler *rh,
                                       struct MHD_Connection *connection,
-                                      void **connection_cls,
-                                      const char *upload_data,
-                                      size_t *upload_data_size)
+                                      const char *const args[])
 {
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
+  (void) args;
   return TALER_MHD_reply_with_error (connection,
                                      rh->response_code,
                                      TALER_EC_METHOD_INVALID,
diff --git a/src/exchange/taler-exchange-httpd_mhd.h 
b/src/exchange/taler-exchange-httpd_mhd.h
index 16fc5a01..0364f046 100644
--- a/src/exchange/taler-exchange-httpd_mhd.h
+++ b/src/exchange/taler-exchange-httpd_mhd.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -34,17 +34,13 @@
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_static_response (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_static_response (const struct TEH_RequestHandler *rh,
                                  struct MHD_Connection *connection,
-                                 void **connection_cls,
-                                 const char *upload_data,
-                                 size_t *upload_data_size);
+                                 const char *const args[]);
 
 
 /**
@@ -53,40 +49,13 @@ TEH_MHD_handler_static_response (struct TEH_RequestHandler 
*rh,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_agpl_redirect (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_agpl_redirect (const struct TEH_RequestHandler *rh,
                                struct MHD_Connection *connection,
-                               void **connection_cls,
-                               const char *upload_data,
-                               size_t *upload_data_size);
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply from varargs.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param response_code HTTP response code to use
- * @param do_cache can the response be cached? (0: no, 1: yes)
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD result code
- */
-int
-TEH_MHD_helper_send_json_pack (struct TEH_RequestHandler *rh,
-                               struct MHD_Connection *connection,
-                               void *connection_cls,
-                               int response_code,
-                               int do_cache,
-                               const char *fmt,
-                               ...);
+                               const char *const args[]);
 
 
 /**
@@ -95,17 +64,13 @@ TEH_MHD_helper_send_json_pack (struct TEH_RequestHandler 
*rh,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_MHD_handler_send_json_pack_error (struct TEH_RequestHandler *rh,
+TEH_MHD_handler_send_json_pack_error (const struct TEH_RequestHandler *rh,
                                       struct MHD_Connection *connection,
-                                      void **connection_cls,
-                                      const char *upload_data,
-                                      size_t *upload_data_size);
+                                      const char *const args[]);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_recoup.c 
b/src/exchange/taler-exchange-httpd_recoup.c
index 26bd65b4..f4cd9915 100644
--- a/src/exchange/taler-exchange-httpd_recoup.c
+++ b/src/exchange/taler-exchange-httpd_recoup.c
@@ -562,27 +562,21 @@ verify_and_execute_recoup (struct MHD_Connection 
*connection,
 
 
 /**
- * Handle a "/recoup" request.  Parses the JSON, and, if successful,
- * passes the JSON data to #verify_and_execute_recoup() to
- * further check the details of the operation specified.  If
- * everything checks out, this will ultimately lead to the "/refund"
- * being executed, or rejected.
+ * Handle a "/coins/$COIN_PUB/recoup" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_recoup() to further
+ * check the details of the operation specified.  If everything checks out,
+ * this will ultimately lead to the refund being executed, or rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_RECOUP_handler_recoup (struct TEH_RequestHandler *rh,
-                           struct MHD_Connection *connection,
-                           void **connection_cls,
-                           const char *upload_data,
-                           size_t *upload_data_size)
+TEH_RECOUP_handler_recoup (struct MHD_Connection *connection,
+                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const json_t *root)
 {
-  json_t *json;
   int res;
   struct TALER_CoinPublicInfo coin;
   struct TALER_DenominationBlindingKeyP coin_bks;
@@ -593,8 +587,6 @@ TEH_RECOUP_handler_recoup (struct TEH_RequestHandler *rh,
                                  &coin.denom_pub_hash),
     TALER_JSON_spec_denomination_signature ("denom_sig",
                                             &coin.denom_sig),
-    GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                 &coin.coin_pub),
     GNUNET_JSON_spec_fixed_auto ("coin_blind_key_secret",
                                  &coin_bks),
     GNUNET_JSON_spec_fixed_auto ("coin_sig",
@@ -605,20 +597,10 @@ TEH_RECOUP_handler_recoup (struct TEH_RequestHandler *rh,
     GNUNET_JSON_spec_end ()
   };
 
-  (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &json);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) || (NULL == json) )
-    return MHD_YES;
+  coin.coin_pub = *coin_pub;
   res = TALER_MHD_parse_json_data (connection,
-                                   json,
+                                   root,
                                    spec);
-  json_decref (json);
   if (GNUNET_SYSERR == res)
     return MHD_NO; /* hard failure */
   if (GNUNET_NO == res)
diff --git a/src/exchange/taler-exchange-httpd_recoup.h 
b/src/exchange/taler-exchange-httpd_recoup.h
index 1baefc8e..f86bf60e 100644
--- a/src/exchange/taler-exchange-httpd_recoup.h
+++ b/src/exchange/taler-exchange-httpd_recoup.h
@@ -27,25 +27,20 @@
 
 
 /**
- * Handle a "/recoup" request.  Parses the JSON, and, if successful,
- * passes the JSON data to #verify_and_execute_recoup() to
- * further check the details of the operation specified.  If
- * everything checks out, this will ultimately lead to the "/refund"
- * being executed, or rejected.
+ * Handle a "/coins/$COIN_PUB/recoup" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_recoup() to further
+ * check the details of the operation specified.  If everything checks out,
+ * this will ultimately lead to the refund being executed, or rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_RECOUP_handler_recoup (struct TEH_RequestHandler *rh,
-                           struct MHD_Connection *connection,
-                           void **connection_cls,
-                           const char *upload_data,
-                           size_t *upload_data_size);
+TEH_RECOUP_handler_recoup (struct MHD_Connection *connection,
+                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const json_t *root);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_refresh_link.c 
b/src/exchange/taler-exchange-httpd_refresh_link.c
index 5e436091..6dbaed49 100644
--- a/src/exchange/taler-exchange-httpd_refresh_link.c
+++ b/src/exchange/taler-exchange-httpd_refresh_link.c
@@ -172,43 +172,37 @@ refresh_link_transaction (void *cls,
 
 
 /**
- * Handle a "/refresh/link" request.  Note that for "/refresh/link"
- * we do use a simple HTTP GET, and a HTTP POST!
+ * Handle a "/coins/$COIN_PUB/link" request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 2, first is the coin_pub, 
second must be "link")
  * @return MHD result code
   */
 int
-TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh,
-                                  struct MHD_Connection *connection,
-                                  void **connection_cls,
-                                  const char *upload_data,
-                                  size_t *upload_data_size)
+TEH_REFRESH_handler_link (const struct TEH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          const char *const args[2])
 {
-  int mhd_ret;
-  int res;
   struct HTD_Context ctx;
+  int mhd_ret;
 
   (void) rh;
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
   memset (&ctx,
           0,
           sizeof (ctx));
-  res = TALER_MHD_parse_request_arg_data (connection,
-                                          "coin_pub",
-                                          &ctx.coin_pub,
-                                          sizeof (struct
-                                                  TALER_CoinSpendPublicKeyP));
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if (GNUNET_OK != res)
-    return MHD_YES;
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &ctx.coin_pub,
+                                     sizeof (ctx.coin_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_COINS_INVALID_COIN_PUB,
+                                       "coin public key malformed");
+  }
   ctx.mlist = json_array ();
   if (GNUNET_OK !=
       TEH_DB_run_transaction (connection,
diff --git a/src/exchange/taler-exchange-httpd_refresh_link.h 
b/src/exchange/taler-exchange-httpd_refresh_link.h
index d0fcff33..9469c471 100644
--- a/src/exchange/taler-exchange-httpd_refresh_link.h
+++ b/src/exchange/taler-exchange-httpd_refresh_link.h
@@ -29,21 +29,17 @@
 
 
 /**
- * Handle a "/refresh/link" request
+ * Handle a "/coins/$COIN_PUB/link" request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 2, first is the coin_pub, 
second must be "link")
  * @return MHD result code
   */
 int
-TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh,
-                                  struct MHD_Connection *connection,
-                                  void **connection_cls,
-                                  const char *upload_data,
-                                  size_t *upload_data_size);
+TEH_REFRESH_handler_link (const struct TEH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          const char *const args[2]);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c 
b/src/exchange/taler-exchange-httpd_refresh_melt.c
index c7dc700f..9d92a4ce 100644
--- a/src/exchange/taler-exchange-httpd_refresh_melt.c
+++ b/src/exchange/taler-exchange-httpd_refresh_melt.c
@@ -577,31 +577,24 @@ check_for_denomination_key (struct MHD_Connection 
*connection,
 
 
 /**
- * Handle a "/refresh/melt" request.  Parses the request into the JSON
- * components and then hands things of to #check_for_denomination_key()
- * to validate the melted coins, the signature and execute the melt
- * using handle_refresh_melt().
- *
- * @param rh context of the handler
+ * Handle a "/coins/$COIN_PUB/melt" request.  Parses the request into the JSON
+ * components and then hands things of to #check_for_denomination_key() to
+ * validate the melted coins, the signature and execute the melt using
+ * handle_refresh_melt().
+
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
  */
 int
-TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
-                                  struct MHD_Connection *connection,
-                                  void **connection_cls,
-                                  const char *upload_data,
-                                  size_t *upload_data_size)
+TEH_REFRESH_handler_melt (struct MHD_Connection *connection,
+                          const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                          const json_t *root)
 {
-  json_t *root;
   struct RefreshMeltContext rmc;
   int res;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                 &rmc.refresh_session.coin.coin_pub),
     TALER_JSON_spec_denomination_signature ("denom_sig",
                                             
&rmc.refresh_session.coin.denom_sig),
     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
@@ -615,25 +608,13 @@ TEH_REFRESH_handler_refresh_melt (struct 
TEH_RequestHandler *rh,
     GNUNET_JSON_spec_end ()
   };
 
-  (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &root);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) ||
-       (NULL == root) )
-    return MHD_YES;
-
   memset (&rmc,
           0,
           sizeof (rmc));
+  rmc.refresh_session.coin.coin_pub = *coin_pub;
   res = TALER_MHD_parse_json_data (connection,
                                    root,
                                    spec);
-  json_decref (root);
   if (GNUNET_OK != res)
     return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
 
diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.h 
b/src/exchange/taler-exchange-httpd_refresh_melt.h
index c50fdcb4..41488c81 100644
--- a/src/exchange/taler-exchange-httpd_refresh_melt.h
+++ b/src/exchange/taler-exchange-httpd_refresh_melt.h
@@ -29,25 +29,20 @@
 
 
 /**
- * Handle a "/refresh/melt" request after the first parsing has
- * happened.  We now need to validate the coins being melted and the
- * session signature and then hand things of to execute the melt
- * operation.  This function parses the JSON arrays and then passes
- * processing on to #refresh_melt_transaction().
- *
- * @param rh context of the handler
+ * Handle a "/coins/$COIN_PUB/melt" request.  Parses the request into the JSON
+ * components and then hands things of to #check_for_denomination_key() to
+ * validate the melted coins, the signature and execute the melt using
+ * handle_refresh_melt().
+
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
  */
 int
-TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,
-                                  struct MHD_Connection *connection,
-                                  void **connection_cls,
-                                  const char *upload_data,
-                                  size_t *upload_data_size);
+TEH_REFRESH_handler_melt (struct MHD_Connection *connection,
+                          const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                          const json_t *root);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c 
b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index 1e03c8e7..b7d7fb1c 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -884,30 +884,27 @@ handle_refresh_reveal_json (struct MHD_Connection 
*connection,
 
 
 /**
- * Handle a "/refresh/reveal" request. This time, the client reveals the
+ * Handle a "/refreshes/$RCH/reveal" request. This time, the client reveals the
  * private transfer keys except for the cut-and-choose value returned from
- * "/refresh/melt".  This function parses the revealed keys and secrets and
+ * "/coins/$COIN_PUB/melt".  This function parses the revealed keys and 
secrets and
  * ultimately passes everything to #resolve_refresh_reveal_denominations()
  * which will verify that the revealed information is valid then runs the
  * transaction in #refresh_reveal_transaction() and finally returns the signed
  * refreshed coins.
  *
  * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
+ * @param args array of additional options (length: 2, session hash and the 
string "reveal")
  * @return MHD result code
-  */
+ */
 int
-TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh,
-                                    struct MHD_Connection *connection,
-                                    void **connection_cls,
-                                    const char *upload_data,
-                                    size_t *upload_data_size)
+TEH_REFRESH_handler_reveal (const struct TEH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            const json_t *root,
+                            const char *const args[2])
 {
   int res;
-  json_t *root;
   json_t *coin_evs;
   json_t *transfer_privs;
   json_t *link_sigs;
@@ -924,24 +921,34 @@ TEH_REFRESH_handler_refresh_reveal (struct 
TEH_RequestHandler *rh,
   };
 
   (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &root);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) ||
-       (NULL == root) )
-    return MHD_YES;
-
   memset (&rctx,
           0,
           sizeof (rctx));
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &rctx.rc,
+                                     sizeof (rctx.rc)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_REFRESHES_INVALID_RCH,
+                                       "refresh commitment hash malformed");
+  }
+  if (0 != strcmp (args[1],
+                   "reveal"))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_OPERATION_INVALID,
+                                       "expected 'reveal' operation");
+  }
   res = TALER_MHD_parse_json_data (connection,
                                    root,
                                    spec);
-  json_decref (root);
   if (GNUNET_OK != res)
   {
     GNUNET_break_op (0);
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.h 
b/src/exchange/taler-exchange-httpd_refresh_reveal.h
index 0b0c29b7..afc9adce 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.h
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.h
@@ -29,26 +29,25 @@
 
 
 /**
- * Handle a "/refresh/reveal" request. This time, the client reveals the
+ * Handle a "/refreshes/$RCH/reveal" request. This time, the client reveals the
  * private transfer keys except for the cut-and-choose value returned from
- * "/refresh/melt".  This function parses the revealed keys and secrets and
+ * "/coins/$COIN_PUB/melt".  This function parses the revealed keys and 
secrets and
  * ultimately passes everything to #resolve_refresh_reveal_denominations()
  * which will verify that the revealed information is valid then runs the
  * transaction in #refresh_reveal_transaction() and finally returns the signed
  * refreshed coins.
  *
  * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
+ * @param args array of additional options (length: 2, session hash and the 
string "reveal")
  * @return MHD result code
-  */
+ */
 int
-TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh,
-                                    struct MHD_Connection *connection,
-                                    void **connection_cls,
-                                    const char *upload_data,
-                                    size_t *upload_data_size);
+TEH_REFRESH_handler_reveal (const struct TEH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            const json_t *root,
+                            const char *const args[2]);
+
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_refund.c 
b/src/exchange/taler-exchange-httpd_refund.c
index 8e24b9b4..e7e34e0b 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -532,27 +532,21 @@ verify_and_execute_refund (struct MHD_Connection 
*connection,
 
 
 /**
- * Handle a "/refund" request.  Parses the JSON, and, if successful,
- * passes the JSON data to #verify_and_execute_refund() to
- * further check the details of the operation specified.  If
- * everything checks out, this will ultimately lead to the "/refund"
- * being executed, or rejected.
+ * Handle a "/coins/$COIN_PUB/refund" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_refund() to further
+ * check the details of the operation specified.  If everything checks out,
+ * this will ultimately lead to the refund being executed, or rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh,
-                           struct MHD_Connection *connection,
-                           void **connection_cls,
-                           const char *upload_data,
-                           size_t *upload_data_size)
+TEH_REFUND_handler_refund (struct MHD_Connection *connection,
+                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const json_t *root)
 {
-  json_t *json;
   int res;
   struct TALER_EXCHANGEDB_Refund refund;
   struct GNUNET_JSON_Specification spec[] = {
@@ -560,7 +554,6 @@ TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh,
     TALER_JSON_spec_amount ("refund_fee", &refund.details.refund_fee),
     GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
                                  &refund.details.h_contract_terms),
-    GNUNET_JSON_spec_fixed_auto ("coin_pub", &refund.coin.coin_pub),
     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &refund.details.merchant_pub),
     GNUNET_JSON_spec_uint64 ("rtransaction_id",
                              &refund.details.rtransaction_id),
@@ -568,20 +561,10 @@ TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh,
     GNUNET_JSON_spec_end ()
   };
 
-  (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &json);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) || (NULL == json) )
-    return MHD_YES;
+  refund.coin.coin_pub = *coin_pub;
   res = TALER_MHD_parse_json_data (connection,
-                                   json,
+                                   root,
                                    spec);
-  json_decref (json);
   if (GNUNET_SYSERR == res)
     return MHD_NO; /* hard failure */
   if (GNUNET_NO == res)
diff --git a/src/exchange/taler-exchange-httpd_refund.h 
b/src/exchange/taler-exchange-httpd_refund.h
index 4f2b868e..b79419f1 100644
--- a/src/exchange/taler-exchange-httpd_refund.h
+++ b/src/exchange/taler-exchange-httpd_refund.h
@@ -29,24 +29,19 @@
 
 
 /**
- * Handle a "/refund" request.  Parses the JSON, and, if successful,
- * passes the JSON data to #verify_and_execute_refund() to
- * further check the details of the operation specified.  If
- * everything checks out, this will ultimately lead to the "/refund"
- * being executed, or rejected.
+ * Handle a "/coins/$COIN_PUB/refund" request.  Parses the JSON, and, if
+ * successful, passes the JSON data to #verify_and_execute_refund() to further
+ * check the details of the operation specified.  If everything checks out,
+ * this will ultimately lead to the refund being executed, or rejected.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param coin_pub public key of the coin
+ * @param root uploaded JSON data
  * @return MHD result code
   */
 int
-TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh,
-                           struct MHD_Connection *connection,
-                           void **connection_cls,
-                           const char *upload_data,
-                           size_t *upload_data_size);
+TEH_REFUND_handler_refund (struct MHD_Connection *connection,
+                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const json_t *root);
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c 
b/src/exchange/taler-exchange-httpd_reserve_status.c
index e2d35aae..25127125 100644
--- a/src/exchange/taler-exchange-httpd_reserve_status.c
+++ b/src/exchange/taler-exchange-httpd_reserve_status.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -15,7 +15,7 @@
 */
 /**
  * @file taler-exchange-httpd_reserve_status.c
- * @brief Handle /reserve/status requests
+ * @brief Handle /reserves/$RESERVE_PUB GET requests
  * @author Florian Dold
  * @author Benedikt Mueller
  * @author Christian Grothoff
@@ -114,42 +114,37 @@ reserve_status_transaction (void *cls,
 
 
 /**
- * Handle a "/reserve/status" request.  Parses the
- * given "reserve_pub" argument (which should contain the
+ * Handle a GET "/reserves/" request.  Parses the
+ * given "reserve_pub" in @a args (which should contain the
  * EdDSA public key of a reserve) and then respond with the
  * status of the reserve.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 1, just the reserve_pub)
  * @return MHD result code
  */
 int
-TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
+TEH_RESERVE_handler_reserve_status (const struct TEH_RequestHandler *rh,
                                     struct MHD_Connection *connection,
-                                    void **connection_cls,
-                                    const char *upload_data,
-                                    size_t *upload_data_size)
+                                    const char *const args[1])
 {
   struct ReserveStatusContext rsc;
-  int res;
   int mhd_ret;
 
   (void) rh;
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
-  res = TALER_MHD_parse_request_arg_data (connection,
-                                          "reserve_pub",
-                                          &rsc.reserve_pub,
-                                          sizeof (struct
-                                                  TALER_ReservePublicKeyP));
-  if (GNUNET_SYSERR == res)
-    return MHD_NO; /* internal error */
-  if (GNUNET_NO == res)
-    return MHD_YES; /* parse error */
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &rsc.reserve_pub,
+                                     sizeof (rsc.reserve_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_RESERVES_INVALID_RESERVE_PUB,
+                                       "reserve public key malformed");
+  }
   rsc.rh = NULL;
   if (GNUNET_OK !=
       TEH_DB_run_transaction (connection,
diff --git a/src/exchange/taler-exchange-httpd_reserve_status.h 
b/src/exchange/taler-exchange-httpd_reserve_status.h
index 67eba230..584bd3dc 100644
--- a/src/exchange/taler-exchange-httpd_reserve_status.h
+++ b/src/exchange/taler-exchange-httpd_reserve_status.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -15,7 +15,7 @@
 */
 /**
  * @file taler-exchange-httpd_reserve_status.h
- * @brief Handle /reserve/status requests
+ * @brief Handle /reserves/$RESERVE_PUB GET requests
  * @author Florian Dold
  * @author Benedikt Mueller
  * @author Christian Grothoff
@@ -26,24 +26,21 @@
 #include <microhttpd.h>
 #include "taler-exchange-httpd.h"
 
+
 /**
- * Handle a "/reserve/status" request.  Parses the
- * given "reserve_pub" argument (which should contain the
+ * Handle a GET "/reserves/" request.  Parses the
+ * given "reserve_pub" in @a args (which should contain the
  * EdDSA public key of a reserve) and then respond with the
  * status of the reserve.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 1, just the reserve_pub)
  * @return MHD result code
-  */
+ */
 int
-TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
+TEH_RESERVE_handler_reserve_status (const struct TEH_RequestHandler *rh,
                                     struct MHD_Connection *connection,
-                                    void **connection_cls,
-                                    const char *upload_data,
-                                    size_t *upload_data_size);
+                                    const char *const args[1]);
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c 
b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
index 9daad0a0..25747eff 100644
--- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
@@ -335,30 +335,27 @@ withdraw_transaction (void *cls,
 
 
 /**
- * Handle a "/reserve/withdraw" request.  Parses the "reserve_pub"
- * EdDSA key of the reserve and the requested "denom_pub" which
- * specifies the key/value of the coin to be withdrawn, and checks
- * that the signature "reserve_sig" makes this a valid withdrawal
- * request from the specified reserve.  If so, the envelope
- * with the blinded coin "coin_ev" is passed down to execute the
- * withdrawl operation.
+ * Handle a "/reserves/$RESERVE_PUB/withdraw" request.  Parses the
+ * "reserve_pub" EdDSA key of the reserve and the requested "denom_pub" which
+ * specifies the key/value of the coin to be withdrawn, and checks that the
+ * signature "reserve_sig" makes this a valid withdrawal request from the
+ * specified reserve.  If so, the envelope with the blinded coin "coin_ev" is
+ * passed down to execute the withdrawl operation.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param root uploaded JSON data
+ * @param args array of additional options (first must be the
+ *         reserve public key, the second one should be "withdraw")
  * @return MHD result code
  */
 int
-TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh,
+TEH_RESERVE_handler_reserve_withdraw (const struct TEH_RequestHandler *rh,
                                       struct MHD_Connection *connection,
-                                      void **connection_cls,
-                                      const char *upload_data,
-                                      size_t *upload_data_size)
+                                      const json_t *root,
+                                      const char *const args[2])
 {
   struct WithdrawContext wc;
-  json_t *root;
   int res;
   int mhd_ret;
   unsigned int hc;
@@ -369,8 +366,6 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
     GNUNET_JSON_spec_varsize ("coin_ev",
                               (void **) &wc.blinded_msg,
                               &wc.blinded_msg_len),
-    GNUNET_JSON_spec_fixed_auto ("reserve_pub",
-                                 &wc.wsrd.reserve_pub),
     GNUNET_JSON_spec_fixed_auto ("reserve_sig",
                                  &wc.signature),
     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
@@ -379,19 +374,22 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
   };
 
   (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &root);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) || (NULL == root) )
-    return MHD_YES;
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &wc.wsrd.reserve_pub,
+                                     sizeof (wc.wsrd.reserve_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_RESERVES_INVALID_RESERVE_PUB,
+                                       "reserve public key malformed");
+  }
+
   res = TALER_MHD_parse_json_data (connection,
                                    root,
                                    spec);
-  json_decref (root);
   if (GNUNET_OK != res)
     return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
   wc.key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.h 
b/src/exchange/taler-exchange-httpd_reserve_withdraw.h
index 67b4cad0..c3e56eaa 100644
--- a/src/exchange/taler-exchange-httpd_reserve_withdraw.h
+++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2014-2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -28,26 +28,24 @@
 
 
 /**
- * Handle a "/reserve/withdraw" request.  Parses the "reserve_pub"
- * EdDSA key of the reserve and the requested "denom_pub" which
- * specifies the key/value of the coin to be withdrawn, and checks
- * that the signature "reserve_sig" makes this a valid withdrawl
- * request from the specified reserve.  If so, the envelope
- * with the blinded coin "coin_ev" is passed down to execute the
- * withdrawl operation.
+ * Handle a "/reserves/$RESERVE_PUB/withdraw" request.  Parses the
+ * "reserve_pub" EdDSA key of the reserve and the requested "denom_pub" which
+ * specifies the key/value of the coin to be withdrawn, and checks that the
+ * signature "reserve_sig" makes this a valid withdrawl request from the
+ * specified reserve.  If so, the envelope with the blinded coin "coin_ev" is
+ * passed down to execute the withdrawl operation.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param root uploaded JSON data
+ * @param args array of additional options (first must be the
+ *         reserve public key, the second one should be "withdraw")
  * @return MHD result code
   */
 int
-TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh,
+TEH_RESERVE_handler_reserve_withdraw (const struct TEH_RequestHandler *rh,
                                       struct MHD_Connection *connection,
-                                      void **connection_cls,
-                                      const char *upload_data,
-                                      size_t *upload_data_size);
+                                      const json_t *root,
+                                      const char *const args[2]);
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_terms.c 
b/src/exchange/taler-exchange-httpd_terms.c
index 47905f60..121e1c78 100644
--- a/src/exchange/taler-exchange-httpd_terms.c
+++ b/src/exchange/taler-exchange-httpd_terms.c
@@ -43,22 +43,16 @@ static struct TALER_MHD_Legal *pp;
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_handler_terms (struct TEH_RequestHandler *rh,
+TEH_handler_terms (const struct TEH_RequestHandler *rh,
                    struct MHD_Connection *connection,
-                   void **connection_cls,
-                   const char *upload_data,
-                   size_t *upload_data_size)
+                   const char *const args[])
 {
   (void) rh;
-  (void) upload_data;
-  (void) upload_data_size;
-  (void) connection_cls;
+  (void) args;
   return TALER_MHD_reply_legal (connection,
                                 tos);
 }
@@ -69,22 +63,16 @@ TEH_handler_terms (struct TEH_RequestHandler *rh,
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_handler_privacy (struct TEH_RequestHandler *rh,
+TEH_handler_privacy (const struct TEH_RequestHandler *rh,
                      struct MHD_Connection *connection,
-                     void **connection_cls,
-                     const char *upload_data,
-                     size_t *upload_data_size)
+                     const char *const args[])
 {
   (void) rh;
-  (void) upload_data;
-  (void) upload_data_size;
-  (void) connection_cls;
+  (void) args;
   return TALER_MHD_reply_legal (connection,
                                 pp);
 }
diff --git a/src/exchange/taler-exchange-httpd_terms.h 
b/src/exchange/taler-exchange-httpd_terms.h
index 75909df9..7fe7774a 100644
--- a/src/exchange/taler-exchange-httpd_terms.h
+++ b/src/exchange/taler-exchange-httpd_terms.h
@@ -34,34 +34,27 @@
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_handler_terms (struct TEH_RequestHandler *rh,
+TEH_handler_terms (const struct TEH_RequestHandler *rh,
                    struct MHD_Connection *connection,
-                   void **connection_cls,
-                   const char *upload_data,
-                   size_t *upload_data_size);
+                   const char *const args[]);
+
 
 /**
  * Handle a "/privacy" request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
  */
 int
-TEH_handler_privacy (struct TEH_RequestHandler *rh,
+TEH_handler_privacy (const struct TEH_RequestHandler *rh,
                      struct MHD_Connection *connection,
-                     void **connection_cls,
-                     const char *upload_data,
-                     size_t *upload_data_size);
+                     const char *const args[]);
 
 
 /**
diff --git a/src/exchange/taler-exchange-httpd_track_transaction.c 
b/src/exchange/taler-exchange-httpd_track_transaction.c
index e8143213..d0f1d0aa 100644
--- a/src/exchange/taler-exchange-httpd_track_transaction.c
+++ b/src/exchange/taler-exchange-httpd_track_transaction.c
@@ -336,62 +336,86 @@ check_and_handle_track_transaction_request (struct 
MHD_Connection *connection,
 
 
 /**
- * Handle a "/track/transaction" request.
+ * Handle a "/deposits/$H_WIRE/$MERCHANT_PUB/$H_CONTRACT_TERMS/$COIN_PUB"
+ * request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 4, contains:
+ *      h_wire, merchant_pub, h_contract_terms and coin_pub)
  * @return MHD result code
- */
+  */
 int
-TEH_TRACKING_handler_track_transaction (struct TEH_RequestHandler *rh,
+TEH_TRACKING_handler_track_transaction (const struct TEH_RequestHandler *rh,
                                         struct MHD_Connection *connection,
-                                        void **connection_cls,
-                                        const char *upload_data,
-                                        size_t *upload_data_size)
+                                        const char *const args[4])
 {
   int res;
-  json_t *json;
   struct TALER_DepositTrackPS tps;
   struct TALER_MerchantSignatureP merchant_sig;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("h_wire", &tps.h_wire),
-    GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &tps.h_contract_terms),
-    GNUNET_JSON_spec_fixed_auto ("coin_pub", &tps.coin_pub),
-    GNUNET_JSON_spec_fixed_auto ("merchant_pub", &tps.merchant),
-    GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig),
-    GNUNET_JSON_spec_end ()
-  };
-
-  (void) rh;
-  res = TALER_MHD_parse_post_json (connection,
-                                   connection_cls,
-                                   upload_data,
-                                   upload_data_size,
-                                   &json);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO;
-  if ( (GNUNET_NO == res) || (NULL == json) )
-    return MHD_YES;
-  res = TALER_MHD_parse_json_data (connection,
-                                   json,
-                                   spec);
-  if (GNUNET_OK != res)
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &tps.h_wire,
+                                     sizeof (tps.h_wire)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_DEPOSITS_INVALID_H_WIRE,
+                                       "wire hash malformed");
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[1],
+                                     strlen (args[1]),
+                                     &tps.merchant,
+                                     sizeof (tps.merchant)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_DEPOSITS_INVALID_MERCHANT_PUB,
+                                       "merchant public key malformed");
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[2],
+                                     strlen (args[2]),
+                                     &tps.h_contract_terms,
+                                     sizeof (tps.h_contract_terms)))
   {
-    json_decref (json);
-    return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_DEPOSITS_INVALID_H_CONTRACT_TERMS,
+                                       "contract terms hash malformed");
   }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[3],
+                                     strlen (args[3]),
+                                     &tps.coin_pub,
+                                     sizeof (tps.coin_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_DEPOSITS_INVALID_COIN_PUB,
+                                       "coin public key malformed");
+  }
+  res = TALER_MHD_parse_request_arg_data (connection,
+                                          "merchant_sig",
+                                          &merchant_sig,
+                                          sizeof (merchant_sig));
+  if (GNUNET_SYSERR == res)
+    return MHD_NO; /* internal error */
+  if (GNUNET_NO == res)
+    return MHD_YES; /* parse error */
   tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS));
   tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION);
-  res = check_and_handle_track_transaction_request (connection,
-                                                    &tps,
-                                                    &tps.merchant,
-                                                    &merchant_sig);
-  GNUNET_JSON_parse_free (spec);
-  json_decref (json);
-  return res;
+  return check_and_handle_track_transaction_request (connection,
+                                                     &tps,
+                                                     &tps.merchant,
+                                                     &merchant_sig);
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_track_transaction.h 
b/src/exchange/taler-exchange-httpd_track_transaction.h
index 929ee638..5f54754f 100644
--- a/src/exchange/taler-exchange-httpd_track_transaction.h
+++ b/src/exchange/taler-exchange-httpd_track_transaction.h
@@ -27,21 +27,19 @@
 
 
 /**
- * Handle a "/track/transaction" request.
+ * Handle a "/deposits/$H_WIRE/$MERCHANT_PUB/$H_CONTRACT_TERMS/$COIN_PUB"
+ * request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 4, contains:
+ *      h_wire, merchant_pub, h_contract_terms and coin_pub)
  * @return MHD result code
   */
 int
-TEH_TRACKING_handler_track_transaction (struct TEH_RequestHandler *rh,
+TEH_TRACKING_handler_track_transaction (const struct TEH_RequestHandler *rh,
                                         struct MHD_Connection *connection,
-                                        void **connection_cls,
-                                        const char *upload_data,
-                                        size_t *upload_data_size);
+                                        const char *const args[4]);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c 
b/src/exchange/taler-exchange-httpd_track_transfer.c
index 1a780c06..cff6045e 100644
--- a/src/exchange/taler-exchange-httpd_track_transfer.c
+++ b/src/exchange/taler-exchange-httpd_track_transfer.c
@@ -482,40 +482,37 @@ free_ctx (struct WtidTransactionContext *ctx)
 
 
 /**
- * Handle a "/track/transfer" request.
+ * Handle a GET "/transfers/$WTID" request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 1, just the wtid)
  * @return MHD result code
  */
 int
-TEH_TRACKING_handler_track_transfer (struct TEH_RequestHandler *rh,
+TEH_TRACKING_handler_track_transfer (const struct TEH_RequestHandler *rh,
                                      struct MHD_Connection *connection,
-                                     void **connection_cls,
-                                     const char *upload_data,
-                                     size_t *upload_data_size)
+                                     const char *const args[1])
 {
   struct WtidTransactionContext ctx;
-  int res;
   int mhd_ret;
 
   (void) rh;
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
-  memset (&ctx, 0, sizeof (ctx));
-  res = TALER_MHD_parse_request_arg_data (connection,
-                                          "wtid",
-                                          &ctx.wtid,
-                                          sizeof (struct
-                                                  
TALER_WireTransferIdentifierRawP));
-  if (GNUNET_SYSERR == res)
-    return MHD_NO; /* internal error */
-  if (GNUNET_NO == res)
-    return MHD_YES; /* parse error */
+  memset (&ctx,
+          0,
+          sizeof (ctx));
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &ctx.wtid,
+                                     sizeof (ctx.wtid)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_TRANSFERS_INVALID_WTID,
+                                       "wire transfer identifier malformed");
+  }
   if (GNUNET_OK !=
       TEH_DB_run_transaction (connection,
                               "run track transfer",
diff --git a/src/exchange/taler-exchange-httpd_track_transfer.h 
b/src/exchange/taler-exchange-httpd_track_transfer.h
index c68cb288..c6bd7c5d 100644
--- a/src/exchange/taler-exchange-httpd_track_transfer.h
+++ b/src/exchange/taler-exchange-httpd_track_transfer.h
@@ -27,20 +27,17 @@
 
 
 /**
- * Handle a "/track/transfer" request.
+ * Handle a GET "/transfers/$WTID" request.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (length: 1, just the wtid)
  * @return MHD result code
  */
 int
-TEH_TRACKING_handler_track_transfer (struct TEH_RequestHandler *rh,
+TEH_TRACKING_handler_track_transfer (const struct TEH_RequestHandler *rh,
                                      struct MHD_Connection *connection,
-                                     void **connection_cls,
-                                     const char *upload_data,
-                                     size_t *upload_data_size);
+                                     const char *const args[1]);
+
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_validation.c 
b/src/exchange/taler-exchange-httpd_validation.c
index e3dd8e86..e55100e1 100644
--- a/src/exchange/taler-exchange-httpd_validation.c
+++ b/src/exchange/taler-exchange-httpd_validation.c
@@ -25,7 +25,6 @@
 #include "taler-exchange-httpd_validation.h"
 #include "taler-exchange-httpd_wire.h"
 #include "taler_exchangedb_lib.h"
-#include "taler_json_lib.h"
 
 
 /**
diff --git a/src/exchange/taler-exchange-httpd_wire.c 
b/src/exchange/taler-exchange-httpd_wire.c
index e4bcbec5..de4e2db4 100644
--- a/src/exchange/taler-exchange-httpd_wire.c
+++ b/src/exchange/taler-exchange-httpd_wire.c
@@ -124,22 +124,16 @@ TEH_WIRE_get_fees (const char *method)
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
   */
 int
-TEH_WIRE_handler_wire (struct TEH_RequestHandler *rh,
+TEH_WIRE_handler_wire (const struct TEH_RequestHandler *rh,
                        struct MHD_Connection *connection,
-                       void **connection_cls,
-                       const char *upload_data,
-                       size_t *upload_data_size)
+                       const char *const args[])
 {
   (void) rh;
-  (void) connection_cls;
-  (void) upload_data;
-  (void) upload_data_size;
+  (void) args;
   GNUNET_assert (NULL != wire_methods);
   return TALER_MHD_reply_json (connection,
                                wire_methods,
diff --git a/src/exchange/taler-exchange-httpd_wire.h 
b/src/exchange/taler-exchange-httpd_wire.h
index 75c60353..ac4ea39c 100644
--- a/src/exchange/taler-exchange-httpd_wire.h
+++ b/src/exchange/taler-exchange-httpd_wire.h
@@ -51,17 +51,13 @@ TEH_WIRE_get_fees (const char *method);
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param args array of additional options (must be empty for this function)
  * @return MHD result code
-  */
+ */
 int
-TEH_WIRE_handler_wire (struct TEH_RequestHandler *rh,
+TEH_WIRE_handler_wire (const struct TEH_RequestHandler *rh,
                        struct MHD_Connection *connection,
-                       void **connection_cls,
-                       const char *upload_data,
-                       size_t *upload_data_size);
+                       const char *const args[]);
 
 
 #endif
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 917ac36d..1c48fe33 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -85,6 +85,32 @@ enum TALER_ErrorCode
    */
   TALER_EC_METHOD_INVALID = 8,
 
+  /**
+   * Operation specified invalid for this URL (resulting in a "NOT
+   * FOUND" for the overall response).
+   */
+  TALER_EC_OPERATION_INVALID = 9,
+
+  /**
+   * There is no endpoint defined for the URL provided by the client
+   * (returned together with a MHD_HTTP_NOT FOUND status code).
+   */
+  TALER_EC_ENDPOINT_UNKNOWN = 10,
+
+  /**
+   * The URI is longer than the longest URI the HTTP server is willing
+   * to parse. Returned together with an HTTP status code of
+   * MHD_HTTP_URI_TOO_LONG.
+   */
+  TALER_EC_URI_TOO_LONG = 11,
+
+  /**
+   * The number of segments included in the URI does not match the
+   * number of segments expected by the endpoint. (returned together
+   * with a MHD_HTTP_NOT FOUND status code).
+   */
+  TALER_EC_WRONG_NUMBER_OF_SEGMENTS = 12,
+
   /**
    * The exchange failed to even just initialize its connection to the
    * database.  This response is provided with HTTP status code
@@ -181,6 +207,50 @@ enum TALER_ErrorCode
    */
   TALER_EC_DB_COIN_HISTORY_STORE_ERROR = 1014,
 
+  /**
+   * The public key of given to a /coins/ handler was malformed.
+   */
+  TALER_EC_COINS_INVALID_COIN_PUB = 1050,
+
+  /**
+   * The public key of given to a /reserves/ handler was malformed.
+   */
+  TALER_EC_RESERVES_INVALID_RESERVE_PUB = 1051,
+
+  /**
+   * The public key of given to a /transfers/ handler was malformed.
+   */
+  TALER_EC_TRANSFERS_INVALID_WTID = 1052,
+
+  /**
+   * The hash of the wire details of given to a /deposits/ handler was
+   * malformed.
+   */
+  TALER_EC_DEPOSITS_INVALID_H_WIRE = 1053,
+
+  /**
+   * The merchant public key given to a /deposits/ handler was
+   * malformed.
+   */
+  TALER_EC_DEPOSITS_INVALID_MERCHANT_PUB = 1054,
+
+  /**
+   * The hash of the contract given to a /deposits/ handler was
+   * malformed.
+   */
+  TALER_EC_DEPOSITS_INVALID_H_CONTRACT_TERMS = 1055,
+
+  /**
+   * The coin public key given to a /deposits/ handler was malformed.
+   */
+  TALER_EC_DEPOSITS_INVALID_COIN_PUB = 1056,
+
+  /**
+   * The hash of the refresh commitment given to a /refreshes/ handler
+   * was malformed.
+   */
+  TALER_EC_REFRESHES_INVALID_RCH = 1057,
+
   /**
    * The given reserve does not have sufficient funds to admit the
    * requested withdraw operation at this time.  The response includes

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]