gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: API change for #6363


From: gnunet
Subject: [taler-merchant] branch master updated: API change for #6363
Date: Sun, 23 Apr 2023 22:58:01 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 154f964a API change for #6363
154f964a is described below

commit 154f964aab5df00cbadaa015474c2b323161aa96
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Apr 23 22:57:55 2023 +0200

    API change for #6363
---
 src/backend/Makefile.am                            |   1 +
 src/backend/taler-merchant-httpd.c                 |   2 +
 src/backend/taler-merchant-httpd.h                 |  12 ++
 src/backend/taler-merchant-httpd_helper.c          | 223 ++++++++++++++++-----
 src/backend/taler-merchant-httpd_helper.h          |  44 +++-
 ...er-merchant-httpd_private-delete-instances-ID.c |  12 ++
 ...taler-merchant-httpd_private-get-instances-ID.c |   3 +
 ...ler-merchant-httpd_private-patch-instances-ID.c | 197 +++++++++++++-----
 .../taler-merchant-httpd_private-post-instances.c  | 169 ++++++++--------
 src/backend/taler-merchant-wirewatch.c             |  45 ++++-
 src/backenddb/Makefile.am                          |   2 +
 src/backenddb/pg_insert_account.c                  |  68 +++++++
 src/backenddb/pg_insert_account.h                  |  43 ++++
 src/backenddb/pg_update_account.c                  |  64 ++++++
 src/backenddb/pg_update_account.h                  |  44 ++++
 src/backenddb/plugin_merchantdb_postgres.c         |  49 +----
 src/backenddb/test_merchantdb.c                    |   3 +
 src/bank/mb_parse.c                                |   5 +
 src/include/taler_merchant_service.h               |  28 ++-
 src/include/taler_merchantdb_plugin.h              |  16 ++
 src/lib/merchant_api_patch_instance.c              |  36 +++-
 src/lib/merchant_api_post_instances.c              |  34 +++-
 src/testing/test_key_rotation.sh                   |   2 +-
 src/testing/test_merchant_instance_auth.sh         |   8 +-
 src/testing/test_merchant_instance_creation.sh     |   6 +-
 src/testing/test_merchant_instance_purge.sh        |   4 +-
 src/testing/test_merchant_instance_response.sh     |   2 +-
 src/testing/test_merchant_kyc.sh                   |   2 +-
 src/testing/test_merchant_order_autocleanup.sh     |   4 +-
 src/testing/test_merchant_order_creation.sh        |   4 +-
 src/testing/test_merchant_product_creation.sh      |   2 +-
 src/testing/test_merchant_reserve_creation.sh      |   2 +-
 src/testing/test_merchant_transfer_tracking.sh     |   4 +-
 src/testing/test_merchant_wirewatch.sh             |   2 +-
 src/testing/testing_api_cmd_patch_instance.c       |  11 +-
 src/testing/testing_api_cmd_post_instances.c       |  11 +-
 36 files changed, 881 insertions(+), 283 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 89fab12c..d5bcda16 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -135,6 +135,7 @@ taler_merchant_httpd_SOURCES = \
 
 taler_merchant_httpd_LDADD = \
   $(top_builddir)/src/backenddb/libtalermerchantdb.la \
+  $(top_builddir)/src/bank/libtalermerchantbank.la \
   -ltalerexchange \
   -ltalertemplating \
   -ltalermhd \
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index bebe9f32..8f455f58 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -240,6 +240,8 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi)
                                  wm);
     GNUNET_free (wm->payto_uri);
     GNUNET_free (wm->wire_method);
+    GNUNET_free (wm->credit_facade_url);
+    json_decref (wm->credit_facade_credentials);
     GNUNET_free (wm);
   }
 
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index 391987ab..6f637934 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -25,6 +25,7 @@
 #include "taler_merchantdb_lib.h"
 #include <taler/taler_mhd_lib.h>
 #include <gnunet/gnunet_mhd_compat.h>
+#include "taler_merchant_bank_lib.h"
 
 /**
  * Shorthand for exit jumps.
@@ -70,6 +71,17 @@ struct TMH_WireMethod
    */
   struct TALER_MerchantWireHashP h_wire;
 
+  /**
+   * Base URL of the credit facade.
+   */
+  char *credit_facade_url;
+
+  /**
+   * Authentication data to access the credit facade.
+   * May be uninitialized if not provided by the client.
+   */
+  json_t *credit_facade_credentials;
+
   /**
    * Is this wire method active (should it be included in new contracts)?
    */
diff --git a/src/backend/taler-merchant-httpd_helper.c 
b/src/backend/taler-merchant-httpd_helper.c
index 149ff3c3..981f5937 100644
--- a/src/backend/taler-merchant-httpd_helper.c
+++ b/src/backend/taler-merchant-httpd_helper.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2014--2021 Taler Systems SA
+  (C) 2014--2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -27,68 +27,177 @@
 #include <taler/taler_templating_lib.h>
 #include <taler/taler_dbevents.h>
 
-/**
- * check @a payto_uris for well-formedness
- *
- * @param payto_uris JSON array of payto URIs (presumably)
- * @return true if they are all valid URIs (and this is an array of strings)
- */
+
+enum GNUNET_GenericReturnValue
+TMH_cmp_wire_account (
+  const json_t *account,
+  const struct TMH_WireMethod *wm)
+{
+  const char *credit_facade_url = NULL;
+  json_t *credit_facade_credentials = NULL;
+  const char *uri;
+  struct GNUNET_JSON_Specification ispec[] = {
+    GNUNET_JSON_spec_string ("payto_uri",
+                             &uri),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_string ("credit_facade_url",
+                               &credit_facade_url),
+      NULL),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_json ("credit_facade_credentials",
+                             &credit_facade_credentials),
+      NULL),
+    GNUNET_JSON_spec_end ()
+  };
+  enum GNUNET_GenericReturnValue res;
+  const char *ename;
+  unsigned int eline;
+
+  res = GNUNET_JSON_parse (account,
+                           ispec,
+                           &ename,
+                           &eline);
+  if (GNUNET_OK != res)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to parse account spec: %s (%u)\n",
+                ename,
+                eline);
+    return GNUNET_SYSERR;
+  }
+  if (0 !=
+      strcmp (wm->payto_uri,
+              uri))
+  {
+    GNUNET_JSON_parse_free (ispec);
+    return GNUNET_SYSERR;
+  }
+  if ( (NULL == credit_facade_url) !=
+       (NULL == wm->credit_facade_url) ||
+       (NULL == credit_facade_credentials) !=
+       (NULL == wm->credit_facade_credentials) )
+  {
+    GNUNET_JSON_parse_free (ispec);
+    return GNUNET_NO;
+  }
+  if ( (NULL != credit_facade_url) &&
+       (0 != strcmp (credit_facade_url,
+                     wm->credit_facade_url)) )
+  {
+    GNUNET_JSON_parse_free (ispec);
+    return GNUNET_NO;
+  }
+  if ( (NULL != credit_facade_credentials) &&
+       (0 != json_equal (credit_facade_credentials,
+                         wm->credit_facade_credentials)) )
+  {
+    GNUNET_JSON_parse_free (ispec);
+    return GNUNET_NO;
+  }
+  GNUNET_JSON_parse_free (ispec);
+  return GNUNET_YES;
+}
+
+
 bool
-TMH_payto_uri_array_valid (const json_t *payto_uris)
+TMH_accounts_array_valid (const json_t *accounts)
 {
-  bool payto_ok = true;
+  unsigned int len;
 
-  if (! json_is_array (payto_uris))
+  if (! json_is_array (accounts))
   {
     GNUNET_break_op (0);
-    payto_ok = false;
+    return false;
   }
-  else
+  len = json_array_size (accounts);
+  for (unsigned int i = 0; i<len; i++)
   {
-    unsigned int len = json_array_size (payto_uris);
+    json_t *payto_uri = json_array_get (accounts,
+                                        i);
+    const char *credit_facade_url = NULL;
+    json_t *credit_facade_credentials = NULL;
+    const char *uri;
+    struct GNUNET_JSON_Specification ispec[] = {
+      GNUNET_JSON_spec_string ("payto_uri",
+                               &uri),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_string ("credit_facade_url",
+                                 &credit_facade_url),
+        NULL),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_json ("credit_facade_credentials",
+                               &credit_facade_credentials),
+        NULL),
+      GNUNET_JSON_spec_end ()
+    };
+    enum GNUNET_GenericReturnValue res;
+    const char *ename;
+    unsigned int eline;
+
+    res = GNUNET_JSON_parse (payto_uri,
+                             ispec,
+                             &ename,
+                             &eline);
+    if (GNUNET_OK != res)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Failed to parse account spec: %s (%u)\n",
+                  ename,
+                  eline);
+      return false;
+    }
 
-    for (unsigned int i = 0; i<len; i++)
+    /* Test for the same payto:// URI being given twice */
+    for (unsigned int j = 0; j<i; j++)
     {
-      json_t *payto_uri = json_array_get (payto_uris,
-                                          i);
-      const char *uri;
-
-      if (! json_is_string (payto_uri))
-        payto_ok = false;
-      uri = json_string_value (payto_uri);
-      /* Test for the same payto:// URI being given twice */
-      for (unsigned int j = 0; j<i; j++)
+      json_t *old_uri = json_array_get (accounts,
+                                        j);
+      if (0 == strcmp (uri,
+                       json_string_value (
+                         json_object_get (old_uri,
+                                          "payto_uri"))))
       {
-        json_t *old_uri = json_array_get (payto_uris,
-                                          j);
-        if (json_equal (payto_uri,
-                        old_uri))
-        {
-          GNUNET_break_op (0);
-          payto_ok = false;
-          break;
-        }
+        GNUNET_break_op (0);
+        GNUNET_JSON_parse_free (ispec);
+        return false;
       }
-      if (! payto_ok)
-        break;
+    }
+    {
+      char *err;
+
+      if (NULL !=
+          (err = TALER_payto_validate (uri)))
       {
-        char *err;
-
-        if (NULL !=
-            (err = TALER_payto_validate (uri)))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                      "Encountered invalid payto://-URI `%s': %s\n",
-                      uri,
-                      err);
-          GNUNET_free (err);
-          payto_ok = false;
-          break;
-        }
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Encountered invalid payto://-URI `%s': %s\n",
+                    uri,
+                    err);
+        GNUNET_free (err);
+        GNUNET_JSON_parse_free (ispec);
+        return false;
       }
     }
+    if ( (NULL != credit_facade_url) ||
+         (NULL != credit_facade_credentials) )
+    {
+      struct TALER_MERCHANT_BANK_AuthenticationData auth;
+
+      if (GNUNET_OK !=
+          TALER_MERCHANT_BANK_auth_parse_json (credit_facade_credentials,
+                                               credit_facade_url,
+                                               &auth))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Invalid credit facade URL or credentials `%s'\n",
+                    credit_facade_url);
+        GNUNET_JSON_parse_free (ispec);
+        return false;
+      }
+      TALER_MERCHANT_BANK_auth_free (&auth);
+    }
+    GNUNET_JSON_parse_free (ispec);
   }
-  return payto_ok;
+  return true;
 }
 
 
@@ -396,14 +505,17 @@ TMH_taxes_array_valid (const json_t *taxes)
 
 
 struct TMH_WireMethod *
-TMH_setup_wire_account (const char *payto_uri)
+TMH_setup_wire_account (
+  const char *payto_uri,
+  const char *credit_facade_url,
+  const json_t *credit_facade_credentials)
 {
   struct TMH_WireMethod *wm;
   char *emsg;
 
   if (NULL != (emsg = TALER_payto_validate (payto_uri)))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Invalid URI `%s': %s\n",
                 payto_uri,
                 emsg);
@@ -412,6 +524,12 @@ TMH_setup_wire_account (const char *payto_uri)
   }
 
   wm = GNUNET_new (struct TMH_WireMethod);
+  if (NULL != credit_facade_url)
+    wm->credit_facade_url
+      = GNUNET_strdup (credit_facade_url);
+  if (NULL != credit_facade_credentials)
+    wm->credit_facade_credentials
+      = json_incref ((json_t*) credit_facade_credentials);
   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
                               &wm->wire_salt,
                               sizeof (wm->wire_salt));
@@ -472,8 +590,9 @@ TMH_check_auth_config (struct MHD_Connection *connection,
             TALER_MHD_reply_with_error (connection,
                                         MHD_HTTP_BAD_REQUEST,
                                         
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
-                                        "bad authentication config")) ?
-           GNUNET_NO : GNUNET_SYSERR;
+                                        "bad authentication config"))
+      ? GNUNET_NO
+      : GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
diff --git a/src/backend/taler-merchant-httpd_helper.h 
b/src/backend/taler-merchant-httpd_helper.h
index 5cee97cc..14156fce 100644
--- a/src/backend/taler-merchant-httpd_helper.h
+++ b/src/backend/taler-merchant-httpd_helper.h
@@ -28,13 +28,13 @@
 #include "taler-merchant-httpd.h"
 
 /**
- * check @a payto_uris for well-formedness
+ * check @a accounts for well-formedness
  *
- * @param payto_uris JSON array of payto URIs (presumably)
- * @return true if they are all valid URIs (and this is an array of strings)
+ * @param accounts JSON array of merchant accounts (presumably)
+ * @return true if they are all valid accounts
  */
 bool
-TMH_payto_uri_array_valid (const json_t *payto_uris);
+TMH_accounts_array_valid (const json_t *accounts);
 
 
 /**
@@ -103,15 +103,45 @@ TMH_template_contract_valid (const json_t 
*template_contract);
  * Setup new wire method for the given @ payto_uri.
  *
  * @param payto_uri already validated payto URI
+ * @param credit_facade_url where to download credit information for this 
account (can be NULL)
+ * @param credit_facade_credentials credentials for the @a credit_facade_url
  * @return new wire method object, never fails
  */
 struct TMH_WireMethod *
-TMH_setup_wire_account (const char *payto_uri);
+TMH_setup_wire_account (
+  const char *payto_uri,
+  const char *credit_facade_url,
+  const json_t *credit_facade_credentials);
+
 
 /**
- * FIXME: document
+ * Test if JSON spec @a account for a wire method is equal to the given @a wm.
+ *
+ * @param account JSON spec for a merchant account
+ * @param wm known wire method
+ * @return #GNUNET_YES if both specifications are equal
+ *  #GNUNET_NO if the specifications are for
+ *      the same account but differ in the credit facade
+ *  #GNUNET_SYSERR if the specs are for different accounts
+ *     or if @a account is malformed
  */
+enum GNUNET_GenericReturnValue
+TMH_cmp_wire_account (
+  const json_t *account,
+  const struct TMH_WireMethod *wm);
 
+
+/**
+ * Check that the provided authentication configuration
+ * is valid.
+ *
+ * @param connection connection to use for returning errors
+ * @param jauth JSON with authentication data
+ * @param[out] auth_token set to the authentication token
+ * @return #GNUNET_OK on success,
+ *   #GNUNET_NO if an error was returned on @a connection
+ *   #GNUNET_SYSERR if we failed to return an error on @a connection
+ */
 enum GNUNET_GenericReturnValue
 TMH_check_auth_config (struct MHD_Connection *connection,
                        const json_t *jauth,
@@ -144,7 +174,6 @@ TMH_uuid_from_string (const char *uuids,
     GNUNET_JSON_pack_object_incref ("exchange_reply", (json_t *) (hr)->reply))
 
 
-
 /**
  * TMH_trigger_webhook is a function that need to be use when someone
  * pay. Merchant need to have a notification.
@@ -159,5 +188,4 @@ TMH_trigger_webhook (const char *instance,
                      const json_t *args);
 
 
-
 #endif
diff --git a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c 
b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
index 2791d6d7..8862eadd 100644
--- a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
@@ -21,6 +21,7 @@
 #include "platform.h"
 #include "taler-merchant-httpd_private-delete-instances-ID.h"
 #include <taler/taler_json_lib.h>
+#include <taler/taler_dbevents.h>
 
 
 /**
@@ -52,6 +53,17 @@ delete_instances_ID (struct TMH_MerchantInstance *mi,
   else
     qs = TMH_db->delete_instance_private_key (TMH_db->cls,
                                               mi->settings.id);
+  {
+    struct GNUNET_DB_EventHeaderP es = {
+      .size = htons (sizeof (es)),
+      .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
+    };
+
+    TMH_db->event_notify (TMH_db->cls,
+                          &es,
+                          NULL,
+                          0);
+  }
   switch (qs)
   {
   case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID.c 
b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
index c51d3de0..d2e3d937 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
@@ -52,6 +52,9 @@ get_instances_ID (struct TMH_MerchantInstance *mi,
           GNUNET_JSON_pack_string (
             "payto_uri",
             wm->payto_uri),
+          GNUNET_JSON_pack_string (
+            "credit_facade_url",
+            wm->credit_facade_url),
           GNUNET_JSON_pack_data_auto ("h_wire",
                                       &wm->h_wire),
           GNUNET_JSON_pack_data_auto (
diff --git a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c 
b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
index 77a75da4..9241d069 100644
--- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
@@ -26,6 +26,7 @@
 #include "taler-merchant-httpd_private-patch-instances-ID.h"
 #include "taler-merchant-httpd_helper.h"
 #include <taler/taler_json_lib.h>
+#include <taler/taler_dbevents.h>
 
 
 /**
@@ -62,14 +63,14 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
                     struct TMH_HandlerContext *hc)
 {
   struct TALER_MERCHANTDB_InstanceSettings is;
-  json_t *payto_uris;
+  json_t *accounts;
   const char *name;
   const char *uts = "business";
   struct TMH_WireMethod *wm_head = NULL;
   struct TMH_WireMethod *wm_tail = NULL;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_json ("payto_uris",
-                           &payto_uris),
+    GNUNET_JSON_spec_json ("accounts",
+                           &accounts),
     GNUNET_JSON_spec_string ("name",
                              &name),
     GNUNET_JSON_spec_mark_optional (
@@ -167,7 +168,7 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
                                        "jurisdiction");
   }
 
-  if (! TMH_payto_uri_array_valid (payto_uris))
+  if (! TMH_accounts_array_valid (accounts))
   {
     GNUNET_JSON_parse_free (spec);
     return TALER_MHD_reply_with_error (connection,
@@ -175,7 +176,7 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
                                        TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
                                        NULL);
   }
-  for (unsigned int i = 0; i<MAX_RETRIES; i++)
+  for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
   {
     /* Cleanup after earlier loops */
     {
@@ -255,44 +256,59 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
 
     /* Check for changes in accounts */
     {
-      unsigned int len = json_array_size (payto_uris);
+      unsigned int len = json_array_size (accounts);
       struct TMH_WireMethod *matches[GNUNET_NZL (len)];
-      bool matched;
+      bool updated[GNUNET_NZL (len)];
 
       memset (matches,
               0,
               sizeof (matches));
+      memset (updated,
+              0,
+              sizeof (updated));
       for (struct TMH_WireMethod *wm = mi->wm_head;
            NULL != wm;
            wm = wm->next)
       {
-        const char *uri = wm->payto_uri;
-
-        GNUNET_assert (NULL != uri);
-        matched = false;
+        bool matched = false;
         for (unsigned int i = 0; i<len; i++)
         {
-          const char *str = json_string_value (json_array_get (payto_uris,
-                                                               i));
-          if (0 == strcasecmp (uri,
-                               str))
+          json_t *account = json_array_get (accounts,
+                                            i);
+          enum GNUNET_GenericReturnValue ret;
+
+          ret = TMH_cmp_wire_account (account,
+                                      wm);
+          switch (ret)
           {
+          case GNUNET_SYSERR:
+            continue;
+          case GNUNET_NO:
+            matched = true;
             /* our own existing payto URIs should be unique, that is no
                duplicates in the list, so we cannot match twice */
             GNUNET_assert (NULL == matches[i]);
             matches[i] = wm;
+            updated[i] = true;
+            break;
+          case GNUNET_YES:
             matched = true;
+            /* our own existing payto URIs should be unique, that is no
+               duplicates in the list, so we cannot match twice */
+            GNUNET_assert (NULL == matches[i]);
+            matches[i] = wm;
             break;
           }
         }
+
         /* delete unmatched (= removed) accounts */
         if ( (! matched) &&
              (wm->active) )
         {
           /* Account was REMOVED */
           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                      "Existing account `%s' not found, inactivating it.\n",
-                      uri);
+                      "Existing account `%s' not found, deactivating it.\n",
+                      wm->payto_uri);
           wm->deleting = true;
           qs = TMH_db->inactivate_account (TMH_db->cls,
                                            mi->settings.id,
@@ -306,16 +322,51 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
               goto giveup;
           }
         }
-      }
-      /* Find _new_ accounts */
+      } /* for (wm) */
+
+      /* handle updates */
       for (unsigned int i = 0; i<len; i++)
       {
-        struct TALER_MERCHANTDB_AccountDetails ad;
-        struct TMH_WireMethod *wm;
+        struct TMH_WireMethod *wm = matches[i];
 
-        if (NULL != matches[i])
+        if (! updated[i])
+          continue;
+        GNUNET_assert (NULL != wm);
         {
-          wm = matches[i];
+          struct TALER_MERCHANTDB_AccountDetails ad = {
+            .payto_uri = wm->payto_uri,
+            .h_wire = wm->h_wire,
+            .salt = wm->wire_salt,
+            .credit_facade_url = wm->credit_facade_url,
+            .credit_facade_credentials = wm->credit_facade_credentials,
+            .active = true
+          };
+
+          qs = TMH_db->update_account (TMH_db->cls,
+                                       mi->settings.id,
+                                       &ad);
+          if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+          {
+            TMH_db->rollback (TMH_db->cls);
+            if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+              goto retry;
+            else
+              goto giveup;
+          }
+        } /* ad scope */
+      } /* for possible updates */
+
+      /* Find _new_ accounts or accounts to only enable */
+      for (unsigned int i = 0; i<len; i++)
+      {
+        json_t *account = json_array_get (accounts,
+                                          i);
+        struct TMH_WireMethod *wm = matches[i];
+
+        if (NULL != wm)
+        {
+          if (updated[i])
+            continue; /* handled above */
           if (! wm->active)
           {
             qs = TMH_db->activate_account (TMH_db->cls,
@@ -333,34 +384,82 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
           wm->enabling = true;
           continue;
         }
-        ad.payto_uri = json_string_value (json_array_get (payto_uris,
-                                                          i));
-        GNUNET_assert (NULL != ad.payto_uri);
-        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                    "Adding NEW account `%s'\n",
-                    ad.payto_uri);
-        wm = TMH_setup_wire_account (ad.payto_uri);
-        GNUNET_assert (NULL != wm); /* checked payto_uri validity earlier */
-        GNUNET_CONTAINER_DLL_insert (wm_head,
-                                     wm_tail,
-                                     wm);
-        ad.h_wire = wm->h_wire;
-        ad.salt = wm->wire_salt;
-        ad.active = true;
-        qs = TMH_db->insert_account (TMH_db->cls,
-                                     mi->settings.id,
-                                     &ad);
-        if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+
         {
-          TMH_db->rollback (TMH_db->cls);
-          if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-            goto retry;
-          else
-            goto giveup;
-        }
-      }
-    }
+          const char *credit_facade_url = NULL;
+          json_t *credit_facade_credentials = NULL;
+          const char *uri;
+          struct GNUNET_JSON_Specification ispec[] = {
+            GNUNET_JSON_spec_string ("payto_uri",
+                                     &uri),
+            GNUNET_JSON_spec_mark_optional (
+              GNUNET_JSON_spec_string ("credit_facade_url",
+                                       &credit_facade_url),
+              NULL),
+            GNUNET_JSON_spec_mark_optional (
+              GNUNET_JSON_spec_json ("credit_facade_credentials",
+                                     &credit_facade_credentials),
+              NULL),
+            GNUNET_JSON_spec_end ()
+          };
+          enum GNUNET_GenericReturnValue res;
+
+          res = TALER_MHD_parse_json_data (connection,
+                                           account,
+                                           ispec);
+          if (GNUNET_OK != res)
+            return (GNUNET_NO == res)
+              ? MHD_YES
+              : MHD_NO;
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                      "Adding NEW account `%s'\n",
+                      uri);
+          wm = TMH_setup_wire_account (uri,
+                                       credit_facade_url,
+                                       credit_facade_credentials);
+          GNUNET_assert (NULL != wm); /* checked payto_uri validity earlier */
+          GNUNET_CONTAINER_DLL_insert (wm_head,
+                                       wm_tail,
+                                       wm);
+          GNUNET_JSON_parse_free (ispec);
+        } /* ispec scope */
 
+        {
+          struct TALER_MERCHANTDB_AccountDetails ad = {
+            .payto_uri = wm->payto_uri,
+            .h_wire = wm->h_wire,
+            .salt = wm->wire_salt,
+            .credit_facade_url = wm->credit_facade_url,
+            .credit_facade_credentials = wm->credit_facade_credentials,
+            .active = true
+          };
+
+          qs = TMH_db->insert_account (TMH_db->cls,
+                                       mi->settings.id,
+                                       &ad);
+          if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+          {
+            TMH_db->rollback (TMH_db->cls);
+            if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+              goto retry;
+            else
+              goto giveup;
+          }
+        }   /* ad variable scope */
+      } /* for (i) to find new accounts */
+    } /* scope for checking for account changes */
+
+    {
+      struct GNUNET_DB_EventHeaderP es = {
+        .size = htons (sizeof (es)),
+        .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
+      };
+
+      TMH_db->event_notify (TMH_db->cls,
+                            &es,
+                            NULL,
+                            0);
+    }
     qs = TMH_db->commit (TMH_db->cls);
 retry:
     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c 
b/src/backend/taler-merchant-httpd_private-post-instances.c
index 4d9320ba..c8f443cd 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -25,6 +25,8 @@
 #include "platform.h"
 #include "taler-merchant-httpd_private-post-instances.h"
 #include "taler-merchant-httpd_helper.h"
+#include "taler_merchant_bank_lib.h"
+#include <taler/taler_dbevents.h>
 #include <taler/taler_json_lib.h>
 #include <regex.h>
 
@@ -39,99 +41,51 @@
  * URIs as those already in @a mi (possibly in a different order).
  *
  * @param mi a merchant instance with accounts
- * @param payto_uris a JSON array with accounts (presumably)
+ * @param accounts a JSON array with accounts (presumably)
  * @return true if they are 'equal', false if not or of payto_uris is not an 
array
  */
 static bool
 accounts_equal (const struct TMH_MerchantInstance *mi,
-                json_t *payto_uris)
+                const json_t *accounts)
 {
-  if (! json_is_array (payto_uris))
+  if (! json_is_array (accounts))
     return false;
   {
-    unsigned int len = json_array_size (payto_uris);
-    bool matches[GNUNET_NZL (len)];
-    struct TMH_WireMethod *wm;
+    unsigned int len = json_array_size (accounts);
+    enum GNUNET_GenericReturnValue matches[GNUNET_NZL (len)];
 
-    memset (matches,
-            0,
-            sizeof (matches));
-    for (wm = mi->wm_head;
+    for (unsigned int i = 0; i<len; i++)
+      matches[i] = GNUNET_SYSERR;
+    for (struct TMH_WireMethod *wm = mi->wm_head;
          NULL != wm;
          wm = wm->next)
     {
-      const char *uri = wm->payto_uri;
-
-      GNUNET_assert (NULL != uri);
       for (unsigned int i = 0; i<len; i++)
       {
-        const char *str = json_string_value (json_array_get (payto_uris,
-                                                             i));
+        json_t *account = json_array_get (accounts,
+                                          i);
+        enum GNUNET_GenericReturnValue ret;
 
-        GNUNET_assert (NULL != str);
-        if (0 == strcasecmp (uri,
-                             str))
+        ret = TMH_cmp_wire_account (account,
+                                    wm);
+        if (GNUNET_SYSERR == ret)
+          continue;
+        if (GNUNET_SYSERR != matches[i])
         {
-          if (matches[i])
-          {
-            GNUNET_break (0);
-            return false; /* duplicate entry!? */
-          }
-          matches[i] = true;
-          break;
+          GNUNET_break (0);
+          return false; /* duplicate entry!? */
         }
+        matches[i] = ret;
       }
     }
     for (unsigned int i = 0; i<len; i++)
-      if (! matches[i])
+      if (GNUNET_YES != matches[i])
         return false;
   }
   return true;
 }
 
 
-/**
- * Free memory used by @a wm
- *
- * @param wm wire method to free
- */
-static void
-free_wm (struct TMH_WireMethod *wm)
-{
-  GNUNET_free (wm->payto_uri);
-  GNUNET_free (wm->wire_method);
-  GNUNET_free (wm);
-}
-
-
-/**
- * Free memory used by @a mi.
- *
- * @param mi instance to free
- */
-static void
-free_mi (struct TMH_MerchantInstance *mi)
-{
-  struct TMH_WireMethod *wm;
-
-  while (NULL != (wm = mi->wm_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (mi->wm_head,
-                                 mi->wm_tail,
-                                 wm);
-    free_wm (wm);
-  }
-  GNUNET_free (mi->settings.id);
-  GNUNET_free (mi->settings.name);
-  GNUNET_free (mi->settings.website);
-  GNUNET_free (mi->settings.email);
-  GNUNET_free (mi->settings.logo);
-  json_decref (mi->settings.address);
-  json_decref (mi->settings.jurisdiction);
-  GNUNET_free (mi);
-}
-
-
 /**
  * Generate an instance, given its configuration.
  *
@@ -147,15 +101,15 @@ TMH_private_post_instances (const struct 
TMH_RequestHandler *rh,
 {
   struct TALER_MERCHANTDB_InstanceSettings is;
   struct TALER_MERCHANTDB_InstanceAuthSettings ias;
-  json_t *payto_uris;
+  json_t *accounts;
   const char *auth_token = NULL;
   const char *uts = "business";
   struct TMH_WireMethod *wm_head = NULL;
   struct TMH_WireMethod *wm_tail = NULL;
   json_t *jauth;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_json ("payto_uris",
-                           &payto_uris),
+    GNUNET_JSON_spec_json ("accounts",
+                           &accounts),
     GNUNET_JSON_spec_string ("id",
                              (const char **) &is.id),
     GNUNET_JSON_spec_string ("name",
@@ -208,7 +162,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
              ? MHD_YES
              : MHD_NO;
   }
-
   if (NULL == uts)
     uts = "business";
   if (GNUNET_OK !=
@@ -233,8 +186,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
       return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
   }
 
-  /* check payto_uris for well-formedness */
-  if (! TMH_payto_uri_array_valid (payto_uris))
+  /* check accounts for well-formedness */
+  if (! TMH_accounts_array_valid (accounts))
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_BAD_REQUEST,
                                        TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
@@ -341,12 +294,14 @@ TMH_private_post_instances (const struct 
TMH_RequestHandler *rh,
                              is.address)) &&
            (1 == json_equal (mi->settings.jurisdiction,
                              is.jurisdiction)) &&
-           (GNUNET_OK == TALER_amount_cmp_currency (
+           (GNUNET_OK ==
+            TALER_amount_cmp_currency (
               &mi->settings.default_max_deposit_fee,
               &is.default_max_deposit_fee)) &&
            (0 == TALER_amount_cmp (&mi->settings.default_max_deposit_fee,
                                    &is.default_max_deposit_fee)) &&
-           (GNUNET_OK == TALER_amount_cmp_currency (
+           (GNUNET_OK ==
+            TALER_amount_cmp_currency (
               &mi->settings.default_max_wire_fee,
               &is.default_max_wire_fee)) &&
            (0 == TALER_amount_cmp (&mi->settings.default_max_wire_fee,
@@ -360,7 +315,7 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
                                       ==,
                                       is.default_pay_delay)) &&
            (accounts_equal (mi,
-                            payto_uris)) )
+                            accounts)) )
       {
         GNUNET_JSON_parse_free (spec);
         return TALER_MHD_reply_static (connection,
@@ -382,18 +337,46 @@ TMH_private_post_instances (const struct 
TMH_RequestHandler *rh,
 
   /* convert provided payto URIs into internal data structure with salts */
   {
-    unsigned int len = json_array_size (payto_uris);
+    unsigned int len = json_array_size (accounts);
 
     for (unsigned int i = 0; i<len; i++)
     {
-      json_t *payto_uri = json_array_get (payto_uris,
-                                          i);
+      json_t *account = json_array_get (accounts,
+                                        i);
+      const char *credit_facade_url = NULL;
+      json_t *credit_facade_credentials = NULL;
+      const char *uri;
       struct TMH_WireMethod *wm;
-
-      wm = TMH_setup_wire_account (json_string_value (payto_uri));
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_string ("payto_uri",
+                                 &uri),
+        GNUNET_JSON_spec_mark_optional (
+          GNUNET_JSON_spec_string ("credit_facade_url",
+                                   &credit_facade_url),
+          NULL),
+        GNUNET_JSON_spec_mark_optional (
+          GNUNET_JSON_spec_json ("credit_facade_credentials",
+                                 &credit_facade_credentials),
+          NULL),
+        GNUNET_JSON_spec_end ()
+      };
+      enum GNUNET_GenericReturnValue res;
+
+      res = TALER_MHD_parse_json_data (connection,
+                                       account,
+                                       ispec);
+      if (GNUNET_OK != res)
+        return (GNUNET_NO == res)
+          ? MHD_YES
+          : MHD_NO;
+      wm = TMH_setup_wire_account (uri,
+                                   credit_facade_url,
+                                   credit_facade_credentials);
+      GNUNET_assert (NULL != wm);
       GNUNET_CONTAINER_DLL_insert (wm_head,
                                    wm_tail,
                                    wm);
+      GNUNET_JSON_parse_free (ispec);
     }
   }
 
@@ -446,7 +429,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
                          "post /instances"))
       {
         GNUNET_JSON_parse_free (spec);
-        free_mi (mi);
+        mi->rc = 1;
+        TMH_instance_decref (mi);
         return TALER_MHD_reply_with_error (connection,
                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
                                            TALER_EC_GENERIC_DB_START_FAILED,
@@ -469,7 +453,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
                                           
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS,
                                           is.id);
         GNUNET_JSON_parse_free (spec);
-        free_mi (mi);
+        mi->rc = 1;
+        TMH_instance_decref (mi);
         return ret;
       }
       for (struct TMH_WireMethod *wm = wm_head;
@@ -480,6 +465,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler 
*rh,
           .payto_uri = wm->payto_uri,
           .salt = wm->wire_salt,
           .h_wire = wm->h_wire,
+          .credit_facade_url = wm->credit_facade_url,
+          .credit_facade_credentials = wm->credit_facade_credentials,
           .active = wm->active
         };
 
@@ -497,6 +484,17 @@ TMH_private_post_instances (const struct 
TMH_RequestHandler *rh,
           break;
         goto retry;
       }
+      {
+        struct GNUNET_DB_EventHeaderP es = {
+          .size = htons (sizeof (es)),
+          .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
+        };
+
+        TMH_db->event_notify (TMH_db->cls,
+                              &es,
+                              NULL,
+                              0);
+      }
       qs = TMH_db->commit (TMH_db->cls);
       if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
         qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
@@ -507,7 +505,8 @@ retry:
     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     {
       GNUNET_JSON_parse_free (spec);
-      free_mi (mi);
+      mi->rc = 1;
+      TMH_instance_decref (mi);
       return TALER_MHD_reply_with_error (connection,
                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
                                          TALER_EC_GENERIC_DB_COMMIT_FAILED,
diff --git a/src/backend/taler-merchant-wirewatch.c 
b/src/backend/taler-merchant-wirewatch.c
index 380bcc11..03e317b0 100644
--- a/src/backend/taler-merchant-wirewatch.c
+++ b/src/backend/taler-merchant-wirewatch.c
@@ -22,6 +22,7 @@
 #include <gnunet/gnunet_util_lib.h>
 #include <jansson.h>
 #include <pthread.h>
+#include <taler/taler_dbevents.h>
 #include "taler_merchant_bank_lib.h"
 #include "taler_merchantdb_lib.h"
 #include "taler_merchantdb_plugin.h"
@@ -122,6 +123,12 @@ static struct GNUNET_CURL_Context *ctx;
  */
 static struct GNUNET_CURL_RescheduleContext *rc;
 
+/**
+ * Event handler to learn that the configuration changed
+ * and we should shutdown (to be restarted).
+ */
+static struct GNUNET_DB_EventHandler *eh;
+
 /**
  * Value to return from main(). 0 on success, non-zero on errors.
  */
@@ -209,6 +216,11 @@ shutdown_task (void *cls)
     save (w);
     end_watch (w);
   }
+  if (NULL != eh)
+  {
+    db_plugin->event_listen_cancel (eh);
+    eh = NULL;
+  }
   TALER_MERCHANTDB_plugin_unload (db_plugin);
   db_plugin = NULL;
   cfg = NULL;
@@ -456,6 +468,26 @@ start_watch (
 }
 
 
+/**
+ * Function called on configuration change events received from Postgres.  We
+ * shutdown (and systemd should restart us).
+ *
+ * @param cls closure (NULL)
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
+ */
+static void
+config_changed (void *cls,
+                const void *extra,
+                size_t extra_size)
+{
+  (void) cls;
+  (void) extra;
+  (void) extra_size;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
 /**
  * First task.
  *
@@ -501,7 +533,18 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-  // FIXME: also add notification job!
+  {
+    struct GNUNET_DB_EventHeaderP es = {
+      .size = htons (sizeof (es)),
+      .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
+    };
+
+    eh = db_plugin->event_listen (db_plugin->cls,
+                                  &es,
+                                  GNUNET_TIME_UNIT_FOREVER_REL,
+                                  &config_changed,
+                                  NULL);
+  }
   {
     enum GNUNET_DB_QueryStatus qs;
 
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 189b7a32..020b3f7b 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -54,6 +54,8 @@ libtalermerchantdb_la_LDFLAGS = \
 libtaler_plugin_merchantdb_postgres_la_SOURCES = \
   pg_update_wirewatch_progress.h pg_update_wirewatch_progress.c \
   pg_select_wirewatch_accounts.h pg_select_wirewatch_accounts.c \
+  pg_insert_account.h pg_insert_account.c \
+  pg_update_account.h pg_update_account.c \
   pg_lookup_instances.h pg_lookup_instances.c \
   pg_lookup_transfers.h pg_lookup_transfers.c \
   plugin_merchantdb_postgres.c  pg_helper.h
diff --git a/src/backenddb/pg_insert_account.c 
b/src/backenddb/pg_insert_account.c
new file mode 100644
index 00000000..3b57b0ba
--- /dev/null
+++ b/src/backenddb/pg_insert_account.c
@@ -0,0 +1,68 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022, 2023 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_account.c
+ * @brief Implementation of the insert_account function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_account.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_account (
+  void *cls,
+  const char *id,
+  const struct TALER_MERCHANTDB_AccountDetails *account_details)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (id),
+    GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
+    GNUNET_PQ_query_param_auto_from_type (&account_details->salt),
+    GNUNET_PQ_query_param_string (account_details->payto_uri),
+    NULL ==account_details->credit_facade_url
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (account_details->credit_facade_url),
+    NULL == account_details->credit_facade_credentials
+    ? GNUNET_PQ_query_param_null ()
+    : TALER_PQ_query_param_json (account_details->credit_facade_credentials),
+    GNUNET_PQ_query_param_bool (account_details->active),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "insert_account",
+           "INSERT INTO merchant_accounts"
+           "(merchant_serial"
+           ",h_wire"
+           ",salt"
+           ",payto_uri"
+           ",credit_facade_url"
+           ",credit_facade_credentials"
+           ",active)"
+           " SELECT merchant_serial, $2, $3, $4, $5, $6, $7"
+           " FROM merchant_instances"
+           " WHERE merchant_id=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_account",
+                                             params);
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_insert_account.h
new file mode 100644
index 00000000..463bc527
--- /dev/null
+++ b/src/backenddb/pg_insert_account.h
@@ -0,0 +1,43 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_account.h
+ * @brief implementation of the insert_account function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_INSERT_ACCOUNT_H
+#define PG_INSERT_ACCOUNT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Insert information about an instance's account into our database.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param account_details details about the account
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_account (
+  void *cls,
+  const char *id,
+  const struct TALER_MERCHANTDB_AccountDetails *account_details);
+
+
+#endif
diff --git a/src/backenddb/pg_update_account.c 
b/src/backenddb/pg_update_account.c
new file mode 100644
index 00000000..0a95a94c
--- /dev/null
+++ b/src/backenddb/pg_update_account.c
@@ -0,0 +1,64 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2023 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_account.c
+ * @brief Implementation of the update_account function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_account.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_account (
+  void *cls,
+  const char *id,
+  const struct TALER_MERCHANTDB_AccountDetails *account_details)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (id),
+    GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
+    NULL ==account_details->credit_facade_url
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (account_details->credit_facade_url),
+    NULL == account_details->credit_facade_credentials
+    ? GNUNET_PQ_query_param_null ()
+    : TALER_PQ_query_param_json (account_details->credit_facade_credentials),
+    GNUNET_PQ_query_param_bool (account_details->active),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "update_account",
+           "UPDATE merchant_accounts SET"
+           " credit_facade_url=$3"
+           ",credit_facade_credentials=$4"
+           ",active=$5"
+           " WHERE h_wire=$2"
+           "   AND merchant_serial="
+           "   (SELECT merchant_serial"
+           "      FROM merchant_instances"
+           "      WHERE merchant_id=$1);");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "update_account",
+                                             params);
+}
diff --git a/src/backenddb/pg_update_account.h 
b/src/backenddb/pg_update_account.h
new file mode 100644
index 00000000..52b476d9
--- /dev/null
+++ b/src/backenddb/pg_update_account.h
@@ -0,0 +1,44 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2023 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_account.h
+ * @brief implementation of the update_account function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_ACCOUNT_H
+#define PG_UPDATE_ACCOUNT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Update information about an instance's account in our database.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param account_details details about the account
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_account (
+  void *cls,
+  const char *id,
+  const struct TALER_MERCHANTDB_AccountDetails *account_details);
+
+
+#endif
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 19bd022a..e70d8639 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -30,6 +30,8 @@
 #include <taler/taler_mhd_lib.h>
 #include "taler_merchantdb_plugin.h"
 #include "pg_helper.h"
+#include "pg_insert_account.h"
+#include "pg_update_account.h"
 #include "pg_lookup_instances.h"
 #include "pg_lookup_transfers.h"
 #include "pg_update_wirewatch_progress.h"
@@ -409,37 +411,6 @@ postgres_insert_instance (
 }
 
 
-/**
- * Insert information about an instance's account into our database.
- *
- * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (id),
-    GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
-    GNUNET_PQ_query_param_auto_from_type (&account_details->salt),
-    GNUNET_PQ_query_param_string (account_details->payto_uri),
-    GNUNET_PQ_query_param_bool (account_details->active),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_account",
-                                             params);
-}
-
-
 /**
  * Closure for kyc_status_cb().
  */
@@ -7342,17 +7313,6 @@ postgres_connect (void *cls)
                             " JOIN merchant_kyc"
                             "   USING (account_serial)"
                             " WHERE merchant_instances.merchant_id=$1"),
-    /* for postgres_insert_account() */
-    GNUNET_PQ_make_prepare ("insert_account",
-                            "INSERT INTO merchant_accounts"
-                            "(merchant_serial"
-                            ",h_wire"
-                            ",salt"
-                            ",payto_uri"
-                            ",active)"
-                            " SELECT merchant_serial, $2, $3, $4, $5"
-                            " FROM merchant_instances"
-                            " WHERE merchant_id=$1"),
     /* for postgres_delete_instance_private_key() */
     GNUNET_PQ_make_prepare ("delete_key",
                             "DELETE FROM merchant_keys"
@@ -9732,7 +9692,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->commit = &postgres_commit;
   plugin->lookup_instance_auth = &postgres_lookup_instance_auth;
   plugin->insert_instance = &postgres_insert_instance;
-  plugin->insert_account = &postgres_insert_account;
+  plugin->insert_account
+    = &TMH_PG_insert_account;
+  plugin->update_account
+    = &TMH_PG_update_account;
   plugin->account_kyc_set_status
     = &postgres_account_kyc_set_status;
   plugin->account_kyc_get_status
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 3d7d6b8c..708d8c01 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -153,6 +153,9 @@ free_instance_data (struct InstanceData *instance)
 static void
 make_account (struct TALER_MERCHANTDB_AccountDetails *account)
 {
+  memset (account,
+          0,
+          sizeof (*account));
   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
                                     &account->h_wire.hash);
   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
diff --git a/src/bank/mb_parse.c b/src/bank/mb_parse.c
index bb668e48..c92dead4 100644
--- a/src/bank/mb_parse.c
+++ b/src/bank/mb_parse.c
@@ -129,6 +129,11 @@ TALER_MERCHANT_BANK_auth_parse_json (
 {
   const char *method;
 
+  if (NULL == backend_url)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
   auth->wire_gateway_url = GNUNET_strdup (backend_url);
   method = json_string_value (json_object_get (cred,
                                                "type"));
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 92e18335..723f1b07 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -491,6 +491,30 @@ typedef void
   const struct TALER_MERCHANT_HttpResponse *hr);
 
 
+/**
+ * Information about an account of the merchant.
+ */
+struct TALER_MERCHANT_AccountConfig
+{
+  /**
+   * Payto URI of the account.
+   */
+  const char *payto_uri;
+
+  /**
+   * Optional credit facade for the account.
+   * Can be NULL.
+   */
+  const char *credit_facade_url;
+
+  /**
+   * Credit facade credentials for the account.
+   * Can be NULL.
+   */
+  json_t *credit_facade_credentials;
+
+};
+
 /**
  * Setup an new instance in the backend.
  *
@@ -520,7 +544,7 @@ TALER_MERCHANT_instances_post (
   const char *backend_url,
   const char *instance_id,
   unsigned int accounts_length,
-  const char *payto_uris[],
+  const struct TALER_MERCHANT_AccountConfig accounts[],
   const char *name,
   enum TALER_KYCLOGIC_KycUserType ut,
   const json_t *address,
@@ -594,7 +618,7 @@ TALER_MERCHANT_instance_patch (
   const char *backend_url,
   const char *instance_id,
   unsigned int accounts_length,
-  const char *payto_uris[],
+  const struct TALER_MERCHANT_AccountConfig accounts[],
   const char *name,
   enum TALER_KYCLOGIC_KycUserType ut,
   const json_t *address,
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index cffb9acd..f0ae6589 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -1184,6 +1184,22 @@ struct TALER_MERCHANTDB_Plugin
     const char *id,
     const struct TALER_MERCHANTDB_AccountDetails *account_details);
 
+
+  /**
+   * Update information about an instance's account into our database.
+   *
+   * @param cls closure
+   * @param id identifier of the instance
+   * @param account_details details about the account to update
+   * @return database result code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*update_account)(
+    void *cls,
+    const char *id,
+    const struct TALER_MERCHANTDB_AccountDetails *account_details);
+
+
   /**
    * Delete private key of an instance from our database.
    *
diff --git a/src/lib/merchant_api_patch_instance.c 
b/src/lib/merchant_api_patch_instance.c
index 9d4cea84..240cafd0 100644
--- a/src/lib/merchant_api_patch_instance.c
+++ b/src/lib/merchant_api_patch_instance.c
@@ -159,7 +159,7 @@ TALER_MERCHANT_instance_patch (
   const char *backend_url,
   const char *instance_id,
   unsigned int accounts_length,
-  const char *payto_uris[],
+  const struct TALER_MERCHANT_AccountConfig accounts[],
   const char *name,
   enum TALER_KYCLOGIC_KycUserType ut,
   const json_t *address,
@@ -173,7 +173,7 @@ TALER_MERCHANT_instance_patch (
   void *cb_cls)
 {
   struct TALER_MERCHANT_InstancePatchHandle *iph;
-  json_t *jpayto_uris;
+  json_t *jaccounts;
   json_t *req_obj;
   const char *uts;
 
@@ -183,26 +183,44 @@ TALER_MERCHANT_instance_patch (
     GNUNET_break (0);
     return NULL;
   }
-  jpayto_uris = json_array ();
-  if (NULL == jpayto_uris)
+  jaccounts = json_array ();
+  if (NULL == jaccounts)
   {
     GNUNET_break (0);
     return NULL;
   }
   for (unsigned int i = 0; i<accounts_length; i++)
   {
+    const struct TALER_MERCHANT_AccountConfig *account = &accounts[i];
+    json_t *jaccount;
+
+    jaccount =
+      GNUNET_JSON_PACK (
+        GNUNET_JSON_pack_string (
+          "payto_uri",
+          account->payto_uri),
+        GNUNET_JSON_pack_allow_null (
+          GNUNET_JSON_pack_string (
+            "credit_facade_url",
+            account->credit_facade_url)),
+        GNUNET_JSON_pack_allow_null (
+          GNUNET_JSON_pack_object_incref (
+            "credit_facade_credentials",
+            accounts->credit_facade_credentials))
+        );
+
     if (0 !=
-        json_array_append_new (jpayto_uris,
-                               json_string (payto_uris[i])))
+        json_array_append_new (jaccounts,
+                               jaccount))
     {
       GNUNET_break (0);
-      json_decref (jpayto_uris);
+      json_decref (jaccounts);
       return NULL;
     }
   }
   req_obj = GNUNET_JSON_PACK (
-    GNUNET_JSON_pack_array_steal ("payto_uris",
-                                  jpayto_uris),
+    GNUNET_JSON_pack_array_steal ("accounts",
+                                  jaccounts),
     GNUNET_JSON_pack_string ("name",
                              name),
     GNUNET_JSON_pack_string ("user_type",
diff --git a/src/lib/merchant_api_post_instances.c 
b/src/lib/merchant_api_post_instances.c
index 85069dc3..88ef3a06 100644
--- a/src/lib/merchant_api_post_instances.c
+++ b/src/lib/merchant_api_post_instances.c
@@ -165,7 +165,7 @@ TALER_MERCHANT_instances_post (
   const char *backend_url,
   const char *instance_id,
   unsigned int accounts_length,
-  const char *payto_uris[],
+  const struct TALER_MERCHANT_AccountConfig accounts[],
   const char *name,
   enum TALER_KYCLOGIC_KycUserType ut,
   const json_t *address,
@@ -180,7 +180,7 @@ TALER_MERCHANT_instances_post (
   void *cb_cls)
 {
   struct TALER_MERCHANT_InstancesPostHandle *iph;
-  json_t *jpayto_uris;
+  json_t *jaccounts;
   json_t *req_obj;
   json_t *auth_obj;
   const char *uts;
@@ -219,8 +219,8 @@ TALER_MERCHANT_instances_post (
     GNUNET_break (0);
     return NULL;
   }
-  jpayto_uris = json_array ();
-  if (NULL == jpayto_uris)
+  jaccounts = json_array ();
+  if (NULL == jaccounts)
   {
     json_decref (auth_obj);
     GNUNET_break (0);
@@ -228,19 +228,35 @@ TALER_MERCHANT_instances_post (
   }
   for (unsigned int i = 0; i<accounts_length; i++)
   {
+    const struct TALER_MERCHANT_AccountConfig *account = &accounts[i];
+    json_t *jaccount =
+      GNUNET_JSON_PACK (
+        GNUNET_JSON_pack_string (
+          "payto_uri",
+          account->payto_uri),
+        GNUNET_JSON_pack_allow_null (
+          GNUNET_JSON_pack_string (
+            "credit_facade_url",
+            account->credit_facade_url)),
+        GNUNET_JSON_pack_allow_null (
+          GNUNET_JSON_pack_object_incref (
+            "credit_facade_credentials",
+            accounts->credit_facade_credentials))
+        );
+
     if (0 !=
-        json_array_append_new (jpayto_uris,
-                               json_string (payto_uris[i])))
+        json_array_append_new (jaccounts,
+                               jaccount))
     {
       GNUNET_break (0);
       json_decref (auth_obj);
-      json_decref (jpayto_uris);
+      json_decref (jaccounts);
       return NULL;
     }
   }
   req_obj = GNUNET_JSON_PACK (
-    GNUNET_JSON_pack_array_steal ("payto_uris",
-                                  jpayto_uris),
+    GNUNET_JSON_pack_array_steal ("accounts",
+                                  jaccounts),
     GNUNET_JSON_pack_string ("id",
                              instance_id),
     GNUNET_JSON_pack_string ("name",
diff --git a/src/testing/test_key_rotation.sh b/src/testing/test_key_rotation.sh
index 645ceaf2..2cd5569f 100755
--- a/src/testing/test_key_rotation.sh
+++ b/src/testing/test_key_rotation.sh
@@ -190,7 +190,7 @@ echo "OK"
 echo -n "Setting up merchant instance"
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_auth.sh 
b/src/testing/test_merchant_instance_auth.sh
index 4c3bf0a0..16ab1f09 100755
--- a/src/testing/test_merchant_instance_auth.sh
+++ b/src/testing/test_merchant_instance_auth.sh
@@ -30,7 +30,7 @@ echo -n "Configuring 'default' instance ..."
 
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:new_value"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:new_value"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -65,7 +65,7 @@ do
 done
 
 if [ "x$OK" != "x1" ]
-then 
+then
     exit_skip "Failed to start merchant backend"
 fi
 
@@ -97,14 +97,14 @@ fi
 
 PAY_URL=`jq -e -r .taler_pay_uri < $LAST_RESPONSE`
 
-echo OK order $ORDER_ID with $TOKEN 
+echo OK order $ORDER_ID with $TOKEN
 
 echo -n "Configuring 'second' instance ..."
 
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer '$NEW_SECRET \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:second"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"second","name":"second","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:second"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"second","name":"second","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_creation.sh 
b/src/testing/test_merchant_instance_creation.sh
index 27d35365..1fc65ff5 100755
--- a/src/testing/test_merchant_instance_creation.sh
+++ b/src/testing/test_merchant_instance_creation.sh
@@ -24,7 +24,7 @@ echo -n "Configuring a merchant instance before configuring 
the default instance
 
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"first","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"first","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -40,7 +40,7 @@ echo -n "Configuring default instance ..."
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -55,7 +55,7 @@ echo -n "Configuring a second merchant instance ..."
 
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"second","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"second","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_purge.sh 
b/src/testing/test_merchant_instance_purge.sh
index 01653415..1c3fab2b 100755
--- a/src/testing/test_merchant_instance_purge.sh
+++ b/src/testing/test_merchant_instance_purge.sh
@@ -24,7 +24,7 @@ echo -n "Configuring default instance ..."
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -39,7 +39,7 @@ echo -n "Configuring merchant instance ..."
 
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"test","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"test","name":"test","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_response.sh 
b/src/testing/test_merchant_instance_response.sh
index c05b000f..5f175b0b 100755
--- a/src/testing/test_merchant_instance_response.sh
+++ b/src/testing/test_merchant_instance_response.sh
@@ -45,7 +45,7 @@ fi
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"payto_uris":["payto://x-taler-bank/localhost/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+    -d 
'{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_kyc.sh b/src/testing/test_merchant_kyc.sh
index fabcef87..996a8895 100755
--- a/src/testing/test_merchant_kyc.sh
+++ b/src/testing/test_merchant_kyc.sh
@@ -25,7 +25,7 @@ echo -n "Configuring a merchant instance before configuring 
the default instance
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:8082/43","payto://x-taler-bank/localhost:8082/44"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:8082/43"},{"payto_uri":"payto://x-taler-bank/localhost:8082/44"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_order_autocleanup.sh 
b/src/testing/test_merchant_order_autocleanup.sh
index 9d2c9879..c6266a33 100755
--- a/src/testing/test_merchant_order_autocleanup.sh
+++ b/src/testing/test_merchant_order_autocleanup.sh
@@ -28,7 +28,7 @@ echo -n "Configuring merchant instance ..."
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:8082/43","payto://x-taler-bank/localhost:8082/44"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:8082/43"},{"payto_uri":"payto://x-taler-bank/localhost:8082/44"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -41,7 +41,7 @@ fi
 STATUS=$(curl -H "Content-Type: application/json" -X PATCH \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/instances/default/private/ \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:8082/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:8082/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_order_creation.sh 
b/src/testing/test_merchant_order_creation.sh
index 8226514f..754cdc25 100755
--- a/src/testing/test_merchant_order_creation.sh
+++ b/src/testing/test_merchant_order_creation.sh
@@ -46,7 +46,7 @@ FORTYTHREE=`get_payto_uri fortythree x`
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'$FORTYTHREE'","payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'$FORTYTHREE'"},{"payto_uri":"payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -60,7 +60,7 @@ fi
 STATUS=$(curl -H "Content-Type: application/json" -X PATCH \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/instances/default/private/ \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'$FORTYTHREE'"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'$FORTYTHREE'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_product_creation.sh 
b/src/testing/test_merchant_product_creation.sh
index a69fed3e..738b7d5e 100755
--- a/src/testing/test_merchant_product_creation.sh
+++ b/src/testing/test_merchant_product_creation.sh
@@ -24,7 +24,7 @@ echo -n "Configuring merchant instance ..."
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'$FORTYTHREE'"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'$FORTYTHREE'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_reserve_creation.sh 
b/src/testing/test_merchant_reserve_creation.sh
index 58b6611a..cf231dd5 100755
--- a/src/testing/test_merchant_reserve_creation.sh
+++ b/src/testing/test_merchant_reserve_creation.sh
@@ -28,7 +28,7 @@ FORTYTHREE=`get_payto_uri fortythree x`
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:1'$NEXUS_PORT'/43"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:1'$NEXUS_PORT'/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_transfer_tracking.sh 
b/src/testing/test_merchant_transfer_tracking.sh
index 5205a495..91832e52 100755
--- a/src/testing/test_merchant_transfer_tracking.sh
+++ b/src/testing/test_merchant_transfer_tracking.sh
@@ -47,7 +47,7 @@ GNUNET_PAYTO=`get_payto_uri gnunet x`
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'$TOR_PAYTO'","'$GNUNET_PAYTO'"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'$TOR_PAYTO'"},{"payto_uri":"'$GNUNET_PAYTO'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
@@ -67,7 +67,7 @@ TUTORIAL_PAYTO=`get_payto_uri tutorial x`
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'$SURVEY_PAYTO'","'$TUTORIAL_PAYTO'"],"id":"test","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'$SURVEY_PAYTO'"},{"payto_uri":"'$TUTORIAL_PAYTO'"}],"id":"test","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_wirewatch.sh 
b/src/testing/test_merchant_wirewatch.sh
index a7508110..1c078291 100755
--- a/src/testing/test_merchant_wirewatch.sh
+++ b/src/testing/test_merchant_wirewatch.sh
@@ -158,7 +158,7 @@ GNUNET_PAYTO=$(get_payto_uri gnunet x)
 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     -H 'Authorization: Bearer secret-token:super_secret' \
     http://localhost:9966/management/instances \
-    -d 
'{"auth":{"method":"external"},"payto_uris":["'"$GNUNET_PAYTO"'"],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+    -d 
'{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$GNUNET_PAYTO"'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1",
 
"default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us"
 : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
     -w "%{http_code}" -s -o /dev/null)
 
 if [ "$STATUS" != "204" ]
diff --git a/src/testing/testing_api_cmd_patch_instance.c 
b/src/testing/testing_api_cmd_patch_instance.c
index 4ea0fba1..7ff966e0 100644
--- a/src/testing/testing_api_cmd_patch_instance.c
+++ b/src/testing/testing_api_cmd_patch_instance.c
@@ -171,13 +171,20 @@ patch_instance_run (void *cls,
                     struct TALER_TESTING_Interpreter *is)
 {
   struct PatchInstanceState *pis = cls;
-
+  struct TALER_MERCHANT_AccountConfig accounts[GNUNET_NZL (
+                                                 pis->payto_uris_length)];
+
+  memset (accounts,
+          0,
+          sizeof (accounts));
+  for (unsigned int i = 0; i<pis->payto_uris_length; i++)
+    accounts[i].payto_uri = pis->payto_uris[i];
   pis->is = is;
   pis->iph = TALER_MERCHANT_instance_patch (is->ctx,
                                             pis->merchant_url,
                                             pis->instance_id,
                                             pis->payto_uris_length,
-                                            pis->payto_uris,
+                                            accounts,
                                             pis->name,
                                             TALER_KYCLOGIC_KYC_UT_BUSINESS,
                                             pis->address,
diff --git a/src/testing/testing_api_cmd_post_instances.c 
b/src/testing/testing_api_cmd_post_instances.c
index 61e54e53..4938f6c0 100644
--- a/src/testing/testing_api_cmd_post_instances.c
+++ b/src/testing/testing_api_cmd_post_instances.c
@@ -178,13 +178,20 @@ post_instances_run (void *cls,
                     struct TALER_TESTING_Interpreter *is)
 {
   struct PostInstancesState *pis = cls;
-
+  struct TALER_MERCHANT_AccountConfig accounts[GNUNET_NZL (
+                                                 pis->payto_uris_length)];
+
+  memset (accounts,
+          0,
+          sizeof (accounts));
+  for (unsigned int i = 0; i<pis->payto_uris_length; i++)
+    accounts[i].payto_uri = pis->payto_uris[i];
   pis->is = is;
   pis->iph = TALER_MERCHANT_instances_post (is->ctx,
                                             pis->merchant_url,
                                             pis->instance_id,
                                             pis->payto_uris_length,
-                                            pis->payto_uris,
+                                            accounts,
                                             pis->name,
                                             TALER_KYCLOGIC_KYC_UT_BUSINESS,
                                             pis->address,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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