gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: fix some API differences incl


From: gnunet
Subject: [taler-wallet-core] branch master updated: fix some API differences including whatwg-url params
Date: Thu, 04 Apr 2024 21:25:24 +0200

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

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 072ac43b9 fix some API differences including whatwg-url params
072ac43b9 is described below

commit 072ac43b9f69807b8514eb11f8214637561a2573
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Apr 4 16:24:55 2024 -0300

    fix some API differences including whatwg-url params
---
 packages/aml-backoffice-ui/src/context/config.ts   |   4 +-
 packages/aml-backoffice-ui/src/pages/Cases.tsx     | 398 ++++++++++++---------
 packages/bank-ui/src/context/config.ts             |   4 +-
 packages/bank-ui/src/pages/admin/AdminHome.tsx     |  10 +-
 .../instance/DefaultInstanceFormFields.tsx         |  10 +-
 .../src/components/menu/SideBar.tsx                |  11 +-
 .../src/components/product/ProductForm.tsx         |  16 +-
 .../merchant-backoffice-ui/src/context/session.ts  |  24 +-
 packages/merchant-backoffice-ui/src/hooks/bank.ts  |  31 +-
 .../src/hooks/instance.test.ts                     |  14 +-
 .../merchant-backoffice-ui/src/hooks/instance.ts   |  16 +-
 .../merchant-backoffice-ui/src/hooks/order.test.ts |  10 +-
 packages/merchant-backoffice-ui/src/hooks/order.ts |   8 +-
 packages/merchant-backoffice-ui/src/hooks/otp.ts   |   8 +-
 .../src/hooks/product.test.ts                      |   8 +-
 .../merchant-backoffice-ui/src/hooks/product.ts    |  12 +-
 .../merchant-backoffice-ui/src/hooks/templates.ts  |   8 +-
 .../src/hooks/transfer.test.ts                     |   2 +-
 .../merchant-backoffice-ui/src/hooks/transfer.ts   |   4 +-
 .../merchant-backoffice-ui/src/hooks/webhooks.ts   |   8 +-
 .../src/paths/admin/create/Create.stories.tsx      |   5 +-
 .../src/paths/admin/create/index.tsx               |   2 +-
 .../src/paths/admin/create/stories.tsx             |   1 +
 .../src/paths/admin/list/TableActive.tsx           |  20 +-
 .../src/paths/admin/list/index.tsx                 |   4 +-
 .../src/paths/instance/accounts/create/index.tsx   |   2 +-
 .../src/paths/instance/accounts/list/ListPage.tsx  |  22 +-
 .../src/paths/instance/accounts/list/Table.tsx     |  22 +-
 .../src/paths/instance/accounts/list/index.tsx     |  12 +-
 .../src/paths/instance/accounts/update/index.tsx   |   2 +-
 .../src/paths/instance/details/index.tsx           |   2 +-
 .../src/paths/instance/details/stories.tsx         |   1 +
 .../src/paths/instance/orders/create/index.tsx     |   2 +-
 .../paths/instance/orders/details/DetailPage.tsx   |   9 +-
 .../src/paths/instance/orders/details/index.tsx    |   2 +-
 .../src/paths/instance/orders/list/index.tsx       |   6 +-
 .../otp_devices/create/CreatedSuccessfully.tsx     |   8 +-
 .../paths/instance/otp_devices/create/index.tsx    |   2 +-
 .../src/paths/instance/otp_devices/list/index.tsx  |   2 +-
 .../paths/instance/otp_devices/update/index.tsx    |   2 +-
 .../src/paths/instance/products/create/index.tsx   |   2 +-
 .../src/paths/instance/products/list/index.tsx     |   6 +-
 .../src/paths/instance/products/update/index.tsx   |   2 +-
 .../paths/instance/templates/create/CreatePage.tsx |   8 +-
 .../src/paths/instance/templates/create/index.tsx  |   2 +-
 .../src/paths/instance/templates/list/index.tsx    |   4 +-
 .../src/paths/instance/templates/qr/QrPage.tsx     |   8 +-
 .../paths/instance/templates/update/UpdatePage.tsx |   9 +-
 .../src/paths/instance/templates/update/index.tsx  |   2 +-
 .../src/paths/instance/templates/use/index.tsx     |   2 +-
 .../src/paths/instance/token/index.tsx             |   4 +-
 .../src/paths/instance/transfers/create/index.tsx  |   2 +-
 .../src/paths/instance/update/index.tsx            |   6 +-
 .../src/paths/instance/webhooks/create/index.tsx   |   2 +-
 .../src/paths/instance/webhooks/list/index.tsx     |   2 +-
 .../src/paths/instance/webhooks/update/index.tsx   |   2 +-
 .../src/paths/login/index.tsx                      |  39 +-
 packages/taler-harness/src/index.ts                |  12 +
 packages/taler-util/src/http-client/bank-core.ts   |   8 +-
 packages/taler-util/src/http-client/exchange.ts    |   2 +
 packages/taler-util/src/http-client/merchant.ts    |   4 +-
 packages/taler-util/src/http-client/types.ts       |  24 +-
 packages/taler-util/src/whatwg-url.ts              |   9 +-
 .../src/wallet/AddExchange/index.ts                |   5 +-
 .../src/wallet/AddExchange/state.ts                |  11 +-
 .../src/wallet/AddExchange/views.tsx               | 113 ++++--
 packages/web-util/src/context/activity.ts          |   5 +-
 packages/web-util/src/context/bank-api.ts          |  47 +--
 packages/web-util/src/context/merchant-api.ts      |  64 ++--
 packages/web-util/src/utils/http-impl.sw.ts        |   5 +-
 70 files changed, 638 insertions(+), 507 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/context/config.ts 
b/packages/aml-backoffice-ui/src/context/config.ts
index 0ea491ca4..7004225eb 100644
--- a/packages/aml-backoffice-ui/src/context/config.ts
+++ b/packages/aml-backoffice-ui/src/context/config.ts
@@ -65,7 +65,9 @@ export const ExchangeApiProvider = ({
   useEffect(() => {
     api.getConfig()
       .then((resp) => {
-        if (api.isCompatible(resp.body.version)) {
+        if (resp.type === "fail") {
+          setChecked({ type: "error", error: 
TalerError.fromUncheckedDetail(resp.detail) });
+        }else if (api.isCompatible(resp.body.version)) {
           setChecked({ type: "ok", config: resp.body });
         } else {
           setChecked({ type: "incompatible", result: resp.body, supported: 
api.PROTOCOL_VERSION })
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx 
b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index 88580a4ce..faef0ca54 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -1,168 +1,198 @@
-import { HttpStatusCode, TalerError, TalerExchangeApi, TranslatedString, 
assertUnreachable } from "@gnu-taler/taler-util";
-import { ErrorLoading, Loading, createNewForm, useTranslationContext } from 
"@gnu-taler/web-util/browser";
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU 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.
+
+ GNU 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
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+import {
+  HttpStatusCode,
+  TalerError,
+  TalerExchangeApi,
+  assertUnreachable
+} from "@gnu-taler/taler-util";
+import {
+  ErrorLoading,
+  Loading,
+  createNewForm,
+  useTranslationContext,
+} from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { useCases } from "../hooks/useCases.js";
 import { Pages } from "../pages.js";
 
-import { Officer } from "./Officer.js";
 import { amlStateConverter } from "../utils/converter.js";
 import { AmlExchangeBackend } from "../utils/types.js";
+import { Officer } from "./Officer.js";
 
-export function CasesUI({ records, filter, onChangeFilter, onFirstPage, onNext 
}: { onFirstPage?: () => void, onNext?: () => void, filter: 
AmlExchangeBackend.AmlState, onChangeFilter: (f: AmlExchangeBackend.AmlState) 
=> void, records: TalerExchangeApi.AmlRecord[] }): VNode {
+export function CasesUI({
+  records,
+  filter,
+  onChangeFilter,
+  onFirstPage,
+  onNext,
+}: {
+  onFirstPage?: () => void;
+  onNext?: () => void;
+  filter: AmlExchangeBackend.AmlState;
+  onChangeFilter: (f: AmlExchangeBackend.AmlState) => void;
+  records: TalerExchangeApi.AmlRecord[];
+}): VNode {
   const { i18n } = useTranslationContext();
 
   const form = createNewForm<{ state: AmlExchangeBackend.AmlState }>();
 
-  return <div>
-    <div class="sm:flex sm:items-center">
-      <div class="px-2 sm:flex-auto">
-        <h1 class="text-base font-semibold leading-6 text-gray-900">
-          <i18n.Translate>
-            Cases
-          </i18n.Translate>
-        </h1>
-        <p class="mt-2 text-sm text-gray-700 w-80">
-          <i18n.Translate>
-            A list of all the account with the status
-          </i18n.Translate>
-        </p>
-      </div>
-      <div class="px-2">
-        <form.Provider
-          initial={{ state: filter }}
-          onUpdate={(v) => {
-            onChangeFilter(v.state ?? filter);
-          }}
-          onSubmit={(v) => { }}
-        >
-          <form.InputChoiceHorizontal
-            name="state"
-            label={i18n.str`Filter`}
-            converter={amlStateConverter}
-            choices={[
-              {
-                label: i18n.str`Pending`,
-                value: AmlExchangeBackend.AmlState.pending,
-              },
-              {
-                label: i18n.str`Frozen`,
-                value: AmlExchangeBackend.AmlState.frozen,
-              },
-              {
-                label: i18n.str`Normal`,
-                value: AmlExchangeBackend.AmlState.normal,
-              },
-            ]}
-          />
-
-        </form.Provider>
+  return (
+    <div>
+      <div class="sm:flex sm:items-center">
+        <div class="px-2 sm:flex-auto">
+          <h1 class="text-base font-semibold leading-6 text-gray-900">
+            <i18n.Translate>Cases</i18n.Translate>
+          </h1>
+          <p class="mt-2 text-sm text-gray-700 w-80">
+            <i18n.Translate>
+              A list of all the account with the status
+            </i18n.Translate>
+          </p>
+        </div>
+        <div class="px-2">
+          <form.Provider
+            initial={{ state: filter }}
+            onUpdate={(v) => {
+              onChangeFilter(v.state ?? filter);
+            }}
+            onSubmit={(_v) => {}}
+          >
+            <form.InputChoiceHorizontal
+              name="state"
+              label={i18n.str`Filter`}
+              converter={amlStateConverter}
+              choices={[
+                {
+                  label: i18n.str`Pending`,
+                  value: AmlExchangeBackend.AmlState.pending,
+                },
+                {
+                  label: i18n.str`Frozen`,
+                  value: AmlExchangeBackend.AmlState.frozen,
+                },
+                {
+                  label: i18n.str`Normal`,
+                  value: AmlExchangeBackend.AmlState.normal,
+                },
+              ]}
+            />
+          </form.Provider>
+        </div>
       </div>
-    </div>
-    <div class="mt-8 flow-root">
-      <div class="overflow-x-auto">
-        {!records.length ? (
-          <div>empty result </div>
-        ) : (
-          <div class="inline-block min-w-full py-2 align-middle sm:px-6 
lg:px-8">
-            <table class="min-w-full divide-y divide-gray-300">
-              <thead>
-                <tr>
-                  <th
-                    scope="col"
-                    class="px-3 py-3.5 text-left text-sm font-semibold 
text-gray-900 w-80"
-                  >
-                    <i18n.Translate>
-                      Account Id
-                    </i18n.Translate>
-                  </th>
-                  <th
-                    scope="col"
-                    class="px-3 py-3.5 text-left text-sm font-semibold 
text-gray-900 w-40"
-                  >
-                    <i18n.Translate>
-                      Status
-                    </i18n.Translate>
-                  </th>
-                  <th
-                    scope="col"
-                    class="sm:hidden px-3 py-3.5 text-left text-sm 
font-semibold text-gray-900 w-40"
-                  >
-                    <i18n.Translate>
-                      Threshold
-                    </i18n.Translate>
-                  </th>
-                </tr>
-              </thead>
-              <tbody class="divide-y divide-gray-200 bg-white">
-                {records.map((r) => {
-                  return (
-                    <tr class="hover:bg-gray-100 ">
-                      <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-500 ">
-                        <div class="text-gray-900">
-                          <a
-                            href={Pages.account.url({ account: r.h_payto })}
-                            class="text-indigo-600 hover:text-indigo-900"
-                          >
-                            {r.h_payto.substring(0, 16)}...
-                          </a>
-                        </div>
-                      </td>
-                      <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-500">
-                        {((state: AmlExchangeBackend.AmlState): VNode => {
-                          switch (state) {
-                            case AmlExchangeBackend.AmlState.normal: {
-                              return (
-                                <span class="inline-flex items-center 
rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 
ring-inset ring-green-600/20">
-                                  Normal
-                                </span>
-                              );
-                            }
-                            case AmlExchangeBackend.AmlState.pending: {
-                              return (
-                                <span class="inline-flex items-center 
rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 
ring-inset ring-green-600/20">
-                                  Pending
-                                </span>
-                              );
+      <div class="mt-8 flow-root">
+        <div class="overflow-x-auto">
+          {!records.length ? (
+            <div>empty result </div>
+          ) : (
+            <div class="inline-block min-w-full py-2 align-middle sm:px-6 
lg:px-8">
+              <table class="min-w-full divide-y divide-gray-300">
+                <thead>
+                  <tr>
+                    <th
+                      scope="col"
+                      class="px-3 py-3.5 text-left text-sm font-semibold 
text-gray-900 w-80"
+                    >
+                      <i18n.Translate>Account Id</i18n.Translate>
+                    </th>
+                    <th
+                      scope="col"
+                      class="px-3 py-3.5 text-left text-sm font-semibold 
text-gray-900 w-40"
+                    >
+                      <i18n.Translate>Status</i18n.Translate>
+                    </th>
+                    <th
+                      scope="col"
+                      class="sm:hidden px-3 py-3.5 text-left text-sm 
font-semibold text-gray-900 w-40"
+                    >
+                      <i18n.Translate>Threshold</i18n.Translate>
+                    </th>
+                  </tr>
+                </thead>
+                <tbody class="divide-y divide-gray-200 bg-white">
+                  {records.map((r) => {
+                    return (
+                      <tr key={r.h_payto} class="hover:bg-gray-100 ">
+                        <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-500 ">
+                          <div class="text-gray-900">
+                            <a
+                              href={Pages.account.url({ account: r.h_payto })}
+                              class="text-indigo-600 hover:text-indigo-900"
+                            >
+                              {r.h_payto.substring(0, 16)}...
+                            </a>
+                          </div>
+                        </td>
+                        <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-500">
+                          {((state: AmlExchangeBackend.AmlState): VNode => {
+                            switch (state) {
+                              case AmlExchangeBackend.AmlState.normal: {
+                                return (
+                                  <span class="inline-flex items-center 
rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 
ring-inset ring-green-600/20">
+                                    Normal
+                                  </span>
+                                );
+                              }
+                              case AmlExchangeBackend.AmlState.pending: {
+                                return (
+                                  <span class="inline-flex items-center 
rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 
ring-inset ring-green-600/20">
+                                    Pending
+                                  </span>
+                                );
+                              }
+                              case AmlExchangeBackend.AmlState.frozen: {
+                                return (
+                                  <span class="inline-flex items-center 
rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 
ring-inset ring-green-600/20">
+                                    Frozen
+                                  </span>
+                                );
+                              }
                             }
-                            case AmlExchangeBackend.AmlState.frozen: {
-                              return (
-                                <span class="inline-flex items-center 
rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 
ring-inset ring-green-600/20">
-                                  Frozen
-                                </span>
-                              );
-                            }
-                          }
-                        })(r.current_state)}
-                      </td>
-                      <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-900">
-                        {r.threshold}
-                      </td>
-                    </tr>
-                  );
-                })}
-              </tbody>
-            </table>
-            <Pagination onFirstPage={onFirstPage} onNext={onNext} />
-          </div>
-        )}
+                          })(r.current_state)}
+                        </td>
+                        <td class="whitespace-nowrap px-3 py-5 text-sm 
text-gray-900">
+                          {r.threshold}
+                        </td>
+                      </tr>
+                    );
+                  })}
+                </tbody>
+              </table>
+              <Pagination onFirstPage={onFirstPage} onNext={onNext} />
+            </div>
+          )}
+        </div>
       </div>
     </div>
-  </div>
-
+  );
 }
 
-
 export function Cases() {
-  const [stateFilter, setStateFilter] = 
useState(AmlExchangeBackend.AmlState.pending);
+  const [stateFilter, setStateFilter] = useState(
+    AmlExchangeBackend.AmlState.pending,
+  );
 
   const list = useCases(stateFilter);
 
   if (!list) {
-    return <Loading />
+    return <Loading />;
   }
   if (list instanceof TalerError) {
-    return <ErrorLoading error={list} />
+    return <ErrorLoading error={list} />;
   }
 
   if (list.data.type === "fail") {
@@ -170,34 +200,81 @@ export function Cases() {
       case HttpStatusCode.Unauthorized:
       case HttpStatusCode.Forbidden:
       case HttpStatusCode.NotFound:
-      case HttpStatusCode.Conflict: return <Officer />
-      default: assertUnreachable(list.data)
+      case HttpStatusCode.Conflict:
+        return <Officer />;
+      default:
+        assertUnreachable(list.data);
     }
   }
 
-  const { records } = list.data.body
+  const { records } = list.data.body;
 
-  return <CasesUI
-    records={records}
-    onFirstPage={list.pagination && !list.pagination.isFirstPage ? 
list.pagination.reset : undefined}
-    onNext={list.pagination && !list.pagination.isLastPage ? 
list.pagination.loadMore : undefined}
-    filter={stateFilter}
-    onChangeFilter={setStateFilter}
-  />
+  return (
+    <CasesUI
+      records={records}
+      onFirstPage={
+        list.pagination && !list.pagination.isFirstPage
+          ? list.pagination.reset
+          : undefined
+      }
+      onNext={
+        list.pagination && !list.pagination.isLastPage
+          ? list.pagination.loadMore
+          : undefined
+      }
+      filter={stateFilter}
+      onChangeFilter={setStateFilter}
+    />
+  );
 }
 
-export const PeopleIcon = () => <svg xmlns="http://www.w3.org/2000/svg"; 
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" 
class="w-6 h-6">
-  <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 
11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 
0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
-</svg>
+export const PeopleIcon = () => (
+  <svg
+    xmlns="http://www.w3.org/2000/svg";
+    fill="none"
+    viewBox="0 0 24 24"
+    stroke-width="1.5"
+    stroke="currentColor"
+    class="w-6 h-6"
+  >
+    <path
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 
7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"
+    />
+  </svg>
+);
 
-export const HomeIcon = () => <svg xmlns="http://www.w3.org/2000/svg"; 
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" 
class="w-6 h-6">
-  <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 
12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 
1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 
1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" 
/>
-</svg>
+export const HomeIcon = () => (
+  <svg
+    xmlns="http://www.w3.org/2000/svg";
+    fill="none"
+    viewBox="0 0 24 24"
+    stroke-width="1.5"
+    stroke="currentColor"
+    class="w-6 h-6"
+  >
+    <path
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 
9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 
1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 
1.125-1.125V9.75M8.25 21h8.25"
+    />
+  </svg>
+);
 
-function Pagination({ onFirstPage, onNext }: { onFirstPage?: () => void, 
onNext?: () => void, }) {
-  const { i18n } = useTranslationContext()
+function Pagination({
+  onFirstPage,
+  onNext,
+}: {
+  onFirstPage?: () => void;
+  onNext?: () => void;
+}) {
+  const { i18n } = useTranslationContext();
   return (
-    <nav class="flex items-center justify-between border-t border-gray-200 
bg-white px-4 py-3 sm:px-6 rounded-lg" aria-label="Pagination">
+    <nav
+      class="flex items-center justify-between border-t border-gray-200 
bg-white px-4 py-3 sm:px-6 rounded-lg"
+      aria-label="Pagination"
+    >
       <div class="flex flex-1 justify-between sm:justify-end">
         <button
           class="relative disabled:bg-gray-100 disabled:text-gray-500 
inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold 
text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 
focus-visible:outline-offset-0"
@@ -215,6 +292,5 @@ function Pagination({ onFirstPage, onNext }: { 
onFirstPage?: () => void, onNext?
         </button>
       </div>
     </nav>
-
-  )
+  );
 }
diff --git a/packages/bank-ui/src/context/config.ts 
b/packages/bank-ui/src/context/config.ts
index 9522c72bc..342a65c4f 100644
--- a/packages/bank-ui/src/context/config.ts
+++ b/packages/bank-ui/src/context/config.ts
@@ -125,7 +125,9 @@ export const BankCoreApiProvider = ({
     bankClient
       .getConfig()
       .then((resp) => {
-        if (bankClient.isCompatible(resp.body.version)) {
+        if (resp.type === "fail") {
+          setChecked({ type: "error", error:  
TalerError.fromUncheckedDetail(resp.detail) });
+        } else if (bankClient.isCompatible(resp.body.version)) {
           setChecked({ type: "ok", config: resp.body, hints: [] });
         } else {
           // this API supports version 3.0.3
diff --git a/packages/bank-ui/src/pages/admin/AdminHome.tsx 
b/packages/bank-ui/src/pages/admin/AdminHome.tsx
index 7cdbdb450..acae09b40 100644
--- a/packages/bank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/bank-ui/src/pages/admin/AdminHome.tsx
@@ -31,15 +31,7 @@ import {
 } from "@gnu-taler/web-util/browser";
 import {
   format,
-  getDaysInMonth,
-  getHours,
-  getMonth,
-  getYear,
-  setDate,
-  setHours,
-  setMonth,
-  setYear,
-  sub,
+  sub
 } from "date-fns";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
diff --git 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
index cb4442897..2a24dfbe2 100644
--- 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
+++ 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
@@ -20,10 +20,10 @@
  */
 
 import {
-  useTranslationContext
+  useMerchantApiContext,
+  useTranslationContext,
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
-import { useSessionContext } from "../../context/session.js";
 import { Entity } from "../../paths/admin/create/CreatePage.js";
 import { Input } from "../form/Input.js";
 import { InputDuration } from "../form/InputDuration.js";
@@ -42,15 +42,13 @@ export function DefaultInstanceFormFields({
   showId: boolean;
 }): VNode {
   const { i18n } = useTranslationContext();
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
   return (
     <Fragment>
       {showId && (
         <InputWithAddon<Entity>
           name="id"
-          addonBefore={new URL("instances/", backendUrl).href}
+          addonBefore={new URL("instances/", backendUrl.href).href}
           readonly={readonlyId}
           label={i18n.str`Identifier`}
           tooltip={i18n.str`Name of the instance in URLs. The 'default' 
instance is special in that it is used to administer other instances.`}
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index d6a9308bf..9875ce42e 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -40,12 +40,15 @@ export function Sidebar({ mobile }: Props): VNode {
   const { i18n } = useTranslationContext();
   const kycStatus = useInstanceKYCDetails();
 
-  const needKYC = kycStatus !== undefined && !(kycStatus instanceof 
TalerError) && kycStatus.type === "ok" && !!kycStatus.body;
+  const needKYC =
+    kycStatus !== undefined &&
+    !(kycStatus instanceof TalerError) &&
+    kycStatus.type === "ok" &&
+    !!kycStatus.body;
   const { state, logOut } = useSessionContext();
   const isLoggedIn = state.status === "loggedIn";
   const hasToken = isLoggedIn && state.token !== undefined;
-  const backendURL = state.backendUrl;
-  const { config } = useMerchantApiContext();
+  const { config, url: backendURL } = useMerchantApiContext();
 
   return (
     <aside
@@ -212,7 +215,7 @@ export function Sidebar({ mobile }: Props): VNode {
                 <i class="mdi mdi-web" />
               </span>
               <span class="menu-item-label">
-                {new URL(backendURL).hostname}
+                {backendURL.hostname}
               </span>
             </div>
           </li>
diff --git 
a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx 
b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
index 468e5f635..781d2de2c 100644
--- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
+++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
@@ -19,13 +19,14 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
+import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util";
 import {
+  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { h } from "preact";
 import { useCallback, useEffect, useState } from "preact/hooks";
 import * as yup from "yup";
-import { useSessionContext } from "../../context/session.js";
 import {
   ProductCreateSchema as createSchema,
   ProductUpdateSchema as updateSchema,
@@ -38,7 +39,6 @@ import { InputNumber } from "../form/InputNumber.js";
 import { InputStock, Stock } from "../form/InputStock.js";
 import { InputTaxes } from "../form/InputTaxes.js";
 import { InputWithAddon } from "../form/InputWithAddon.js";
-import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util";
 
 type Entity = TalerMerchantApi.ProductDetail & { product_id: string };
 
@@ -84,11 +84,11 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
     }
   }
   const hasErrors = Object.keys(errors).some(
-    (k) => (errors as any)[k] !== undefined,
+    (k) => (errors as Record<string, unknown>)[k] !== undefined,
   );
 
   const submit = useCallback((): Entity | undefined => {
-    const stock: Stock = (value as any).stock;
+    const stock = (value).stock;
 
     if (!stock) {
       value.total_stock = -1;
@@ -101,7 +101,7 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
           : stock.nextRestock;
       value.address = stock.address;
     }
-    delete (value as any).stock;
+    delete value.stock;
 
     if (typeof value.minimum_age !== "undefined" && value.minimum_age < 1) {
       delete value.minimum_age;
@@ -116,9 +116,7 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
     onSubscribe(hasErrors ? undefined : submit);
   }, [submit, hasErrors]);
 
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
   const { i18n } = useTranslationContext();
 
   return (
@@ -132,7 +130,7 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
         {alreadyExist ? undefined : (
           <InputWithAddon<Entity>
             name="product_id"
-            addonBefore={new URL("product/", backendUrl).href}
+            addonBefore={new URL("product/", backendUrl.href).href}
             label={i18n.str`ID`}
             tooltip={i18n.str`product identification to use in URLs (for 
internal use only)`}
           />
diff --git a/packages/merchant-backoffice-ui/src/context/session.ts 
b/packages/merchant-backoffice-ui/src/context/session.ts
index 98cb27400..7a5ef33d7 100644
--- a/packages/merchant-backoffice-ui/src/context/session.ts
+++ b/packages/merchant-backoffice-ui/src/context/session.ts
@@ -39,7 +39,6 @@ export type SessionState = LoggedIn | LoggedOut | Expired;
 
 interface LoggedIn {
   status: "loggedIn";
-  backendUrl: string;
   isAdmin: boolean;
   instance: string;
   token: AccessToken | undefined;
@@ -52,7 +51,6 @@ interface Impersonate {
 }
 interface Expired {
   status: "expired";
-  backendUrl: string;
   isAdmin: boolean;
   instance: string;
   token?: undefined;
@@ -60,7 +58,6 @@ interface Expired {
 }
 interface LoggedOut {
   status: "loggedOut";
-  backendUrl: string;
   instance: string;
   isAdmin: boolean;
   token?: undefined;
@@ -69,7 +66,6 @@ interface LoggedOut {
 export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> =>
   buildCodecForObject<LoggedIn>()
     .property("status", codecForConstString("loggedIn"))
-    .property("backendUrl", codecForString())
     .property("instance", codecForString())
     .property("impersonate", codecOptional(codecForImpresonate()))
     .property("token", codecOptional(codecForString() as Codec<AccessToken>))
@@ -79,7 +75,6 @@ export const codecForSessionStateLoggedIn = (): 
Codec<LoggedIn> =>
 export const codecForSessionStateExpired = (): Codec<Expired> =>
   buildCodecForObject<Expired>()
     .property("status", codecForConstString("expired"))
-    .property("backendUrl", codecForString())
     .property("instance", codecForString())
     .property("impersonate", codecOptional(codecForImpresonate()))
     .property("isAdmin", codecForBoolean())
@@ -88,7 +83,6 @@ export const codecForSessionStateExpired = (): Codec<Expired> 
=>
 export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> =>
   buildCodecForObject<LoggedOut>()
     .property("status", codecForConstString("loggedOut"))
-    .property("backendUrl", codecForString())
     .property("instance", codecForString())
     .property("isAdmin", codecForBoolean())
     .build("SessionState.LoggedOut");
@@ -121,7 +115,6 @@ export const defaultState = (url: URL): SessionState => {
   return {
     status: "loggedIn",
     instance,
-    backendUrl: url.href,
     isAdmin: instance === DEFAULT_ADMIN_USERNAME,
     token: undefined,
     impersonate: undefined,
@@ -151,7 +144,7 @@ export interface SessionStateHandler {
    * from loggedIn to impersonate
    * @param info
    */
-  impersonate(info: { instance: string; token?: AccessToken }): void;
+  impersonate(info: { instance: string; baseUrl: URL, token?: AccessToken }): 
void;
 }
 
 const SESSION_STATE_KEY = buildStorageKey(
@@ -169,20 +162,19 @@ export const INSTANCE_ID_LOOKUP = 
/\/instances\/([^/]*)\/?$/;
  * base URL.
  */
 export function useSessionContext(): SessionStateHandler {
-  const { url } = useMerchantApiContext();
+  const { url: merchantUrl, changeBackend } = useMerchantApiContext();
 
   const { value: state, update } = useLocalStorage(
     SESSION_STATE_KEY,
-    defaultState(url),
+    defaultState(merchantUrl),
   );
 
   return {
     state,
     logOut() {
-      const instance = inferInstanceName(url);
+      const instance = inferInstanceName(merchantUrl);
       const nextState: SessionState = {
         status: "loggedOut",
-        backendUrl: url.href,
         instance,
         isAdmin: instance === DEFAULT_ADMIN_USERNAME,
       };
@@ -196,9 +188,10 @@ export function useSessionContext(): SessionStateHandler {
       if (state.impersonate === undefined) {
         return;
       }
+      const newURL = new URL(`/`, state.impersonate.originalBackendUrl);
+      changeBackend(newURL);
       const nextState: SessionState = {
         status: "loggedIn",
-        backendUrl: state.impersonate.originalBackendUrl,
         isAdmin: state.impersonate.originalInstance === DEFAULT_ADMIN_USERNAME,
         instance: state.impersonate.originalInstance,
         token: state.impersonate.originalToken,
@@ -211,16 +204,15 @@ export function useSessionContext(): SessionStateHandler {
         // can't impersonate if not loggedin
         return;
       }
+      changeBackend(info.baseUrl);
       const nextState: SessionState = {
         status: "loggedIn",
-        backendUrl: new URL(`instances/${info.instance}`, state.backendUrl)
-          .href,
         isAdmin: info.instance === DEFAULT_ADMIN_USERNAME,
         instance: info.instance,
         // FIXME: bank and merchant should have consistent behavior
         token: info.token?.substring("secret-token:".length) as AccessToken,
         impersonate: {
-          originalBackendUrl: state.backendUrl,
+          originalBackendUrl: merchantUrl.href,
           originalToken: state.token,
           originalInstance: state.instance,
         },
diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts 
b/packages/merchant-backoffice-ui/src/hooks/bank.ts
index e1f2638ed..513314f17 100644
--- a/packages/merchant-backoffice-ui/src/hooks/bank.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts
@@ -17,7 +17,6 @@ import {
   useMerchantApiContext
 } from "@gnu-taler/web-util/browser";
 import { useState } from "preact/hooks";
-import { PAGE_SIZE } from "../utils/constants.js";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } 
from "@gnu-taler/taler-util";
@@ -38,12 +37,12 @@ export function revalidateInstanceBankAccounts() {
 }
 export function useInstanceBankAccounts() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   const [offset, setOffset] = useState<string | undefined>();
 
   async function fetcher([token, bid]: [AccessToken, string]) {
-    return await management.listBankAccounts(token, {
+    return await instance.listBankAccounts(token, {
       limit: 5,
       offset: bid,
       order: "dec",
@@ -55,28 +54,6 @@ export function useInstanceBankAccounts() {
     TalerHttpError
   >([session.token, offset, "listBankAccounts"], fetcher);
 
-  const isLastPage =
-    data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
-  const isFirstPage = !offset;
-
-  const result =
-    data && data.type == "ok" ? structuredClone(data.body.accounts) : [];
-  if (result.length == PAGE_SIZE + 1) {
-    result.pop();
-  }
-  const pagination = {
-    result,
-    isLastPage,
-    isFirstPage,
-    loadNext: () => {
-      if (!result.length) return;
-      setOffset(result[result.length - 1].h_wire);
-    },
-    loadFirst: () => {
-      setOffset(undefined);
-    },
-  };
-
   if (error) return error;
   if (data === undefined) return undefined;
   if (data.type !== "ok") return data;
@@ -93,10 +70,10 @@ export function revalidateBankAccountDetails() {
 }
 export function useBankAccountDetails(h_wire: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([token, wireId]: [AccessToken, string]) {
-    return await management.getBankAccountDetails(token, wireId);
+    return await instance.getBankAccountDetails(token, wireId);
   }
 
   const { data, error } = useSWR<
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts 
b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
index 64f534a06..f409592b0 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
@@ -20,6 +20,7 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
+import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
 import * as tests from "@gnu-taler/web-util/testing";
 import { expect } from "chai";
 import {
@@ -36,7 +37,6 @@ import {
   API_UPDATE_CURRENT_INSTANCE_AUTH,
   API_UPDATE_INSTANCE_BY_ID,
 } from "./urls.js";
-import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
 
 describe("instance api interaction with details", () => {
   it("should evict cache when updating an instance", async () => {
@@ -81,7 +81,7 @@ describe("instance api interaction with details", () => {
               name: "other_name",
             } as TalerMerchantApi.QueryInstancesResponse,
           });
-          api.management.updateCurrentInstance(undefined, {
+          api.instance.updateCurrentInstance(undefined, {
             name: "other_name",
           } as TalerMerchantApi.InstanceReconfigurationMessage);
         },
@@ -242,7 +242,7 @@ describe("instance api interaction with details", () => {
             } as TalerMerchantApi.QueryInstancesResponse,
           });
 
-          api.management.updateCurrentInstanceAuthentication(undefined, {
+          api.instance.updateCurrentInstanceAuthentication(undefined, {
             method: "external"
           });
         },
@@ -380,7 +380,7 @@ describe("instance admin api interaction with listing", () 
=> {
             },
           });
 
-          api.management.createInstance(undefined, {
+          api.instance.createInstance(undefined, {
             name: "other_name",
           } as TalerMerchantApi.InstanceConfigurationMessage)
         },
@@ -470,7 +470,7 @@ describe("instance admin api interaction with listing", () 
=> {
             },
           });
 
-          api.management.deleteInstance(undefined, "the_id");
+          api.instance.deleteInstance(undefined, "the_id");
         },
         ({ query, api }) => {
           expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -628,7 +628,7 @@ describe("instance admin api interaction with listing", () 
=> {
             },
           });
 
-          api.management.deleteInstance(undefined, "the_id", { purge: true })
+          api.instance.deleteInstance(undefined, "the_id", { purge: true })
         },
         ({ query, api }) => {
           expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -712,7 +712,7 @@ describe("instance management api interaction with 
listing", () => {
             },
           });
 
-          api.management.updateCurrentInstance(undefined, {
+          api.instance.updateCurrentInstance(undefined, {
             name: "other_name",
           } as TalerMerchantApi.InstanceConfigurationMessage);
         },
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts 
b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index cc907bd8f..1fa84c9d9 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -33,10 +33,10 @@ export function revalidateInstanceDetails() {
 }
 export function useInstanceDetails() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([token]: [AccessToken]) {
-    return await management.getCurrentInstanceDetails(token);
+    return await instance.getCurrentInstanceDetails(token);
   }
 
   const { data, error } = useSWR<
@@ -58,10 +58,10 @@ export function revalidateInstanceKYCDetails() {
 }
 export function useInstanceKYCDetails() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([token]: [AccessToken]) {
-    return await management.getCurrentIntanceKycStatus(token, {});
+    return await instance.getCurrentIntanceKycStatus(token, {});
   }
 
   const { data, error } = useSWR<
@@ -85,10 +85,10 @@ export function revalidateManagedInstanceDetails() {
 }
 export function useManagedInstanceDetails(instanceId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([token, instanceId]: [AccessToken, string]) {
-    return await management.getInstanceDetails(token, instanceId);
+    return await instance.getInstanceDetails(token, instanceId);
   }
 
   const { data, error } = useSWR<
@@ -110,10 +110,10 @@ export function revalidateBackendInstances() {
 }
 export function useBackendInstances() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([token]: [AccessToken]) {
-    return await management.listInstances(token);
+    return await instance.listInstances(token);
   }
 
   const { data, error } = useSWR<
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.test.ts 
b/packages/merchant-backoffice-ui/src/hooks/order.test.ts
index 243415bdd..1aa2fcf0a 100644
--- a/packages/merchant-backoffice-ui/src/hooks/order.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/order.test.ts
@@ -86,7 +86,7 @@ describe("order api interaction with listing", () => {
             },
           });
 
-          api.management.createOrder(undefined, {
+          api.instance.createOrder(undefined, {
             order: { amount: "ARS:12" as AmountString, summary: "pay me" },
           })
         },
@@ -171,7 +171,7 @@ describe("order api interaction with listing", () => {
             },
           });
 
-          api.management.addRefund(undefined, "1", {
+          api.instance.addRefund(undefined, "1", {
             reason: "double pay",
             refund: "EUR:1" as AmountString,
           })
@@ -247,7 +247,7 @@ describe("order api interaction with listing", () => {
             },
           });
 
-          api.management.deleteOrder(undefined, "1")
+          api.instance.deleteOrder(undefined, "1")
         },
         ({ query, api }) => {
           expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -316,7 +316,7 @@ describe("order api interaction with details", () => {
             } as unknown as TalerMerchantApi.CheckPaymentPaidResponse,
           });
 
-          api.management.addRefund(undefined, "1", {
+          api.instance.addRefund(undefined, "1", {
             reason: "double pay",
             refund: "EUR:1" as AmountString,
           })
@@ -386,7 +386,7 @@ describe("order api interaction with details", () => {
             } as unknown as TalerMerchantApi.CheckPaymentPaidResponse,
           });
 
-          api.management.forgetOrder(undefined, "1", {
+          api.instance.forgetOrder(undefined, "1", {
             fields: ["$.summary"],
           })
         },
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts 
b/packages/merchant-backoffice-ui/src/hooks/order.ts
index 47ddf1c38..b1805f6e3 100644
--- a/packages/merchant-backoffice-ui/src/hooks/order.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/order.ts
@@ -36,10 +36,10 @@ export function revalidateOrderDetails() {
 }
 export function useOrderDetails(oderId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([dId, token]: [string, AccessToken]) {
-    return await management.getOrderDetails(token, dId);
+    return await instance.getOrderDetails(token, dId);
   }
 
   const { data, error } = useSWR<
@@ -65,12 +65,12 @@ export function useInstanceOrders(
   updatePosition: (d: string | undefined) => void = () => { },
 ) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   // const [offset, setOffset] = useState<string | undefined>(args?.position);
 
   async function fetcher([token, o, p, r, w, d]: [AccessToken, string, 
boolean, boolean, boolean, AbsoluteTime]) {
-    return await management.listOrders(token, {
+    return await instance.listOrders(token, {
       limit: PAGE_SIZE,
       offset: o,
       order: "dec",
diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts 
b/packages/merchant-backoffice-ui/src/hooks/otp.ts
index 69e4a0f4f..898a27a69 100644
--- a/packages/merchant-backoffice-ui/src/hooks/otp.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts
@@ -35,12 +35,12 @@ export function revalidateInstanceOtpDevices() {
 }
 export function useInstanceOtpDevices() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   const [offset, setOffset] = useState<string | undefined>();
 
   async function fetcher([token, bid]: [AccessToken, string]) {
-    return await management.listOtpDevices(token, {
+    return await instance.listOtpDevices(token, {
       limit: PAGE_SIZE,
       offset: bid,
       order: "dec",
@@ -68,10 +68,10 @@ export function revalidateOtpDeviceDetails() {
 }
 export function useOtpDeviceDetails(deviceId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([dId, token]: [string, AccessToken]) {
-    return await management.getOtpDeviceDetails(token, dId);
+    return await instance.getOtpDeviceDetails(token, dId);
   }
 
   const { data, error } = useSWR<
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.test.ts 
b/packages/merchant-backoffice-ui/src/hooks/product.test.ts
index 1be00201a..39281241c 100644
--- a/packages/merchant-backoffice-ui/src/hooks/product.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/product.test.ts
@@ -99,7 +99,7 @@ describe("product api interaction with listing", () => {
             } as TalerMerchantApi.ProductDetail,
           });
 
-          api.management.addProduct(undefined, {
+          api.instance.addProduct(undefined, {
             price: "ARS:23",
           } as any);
         },
@@ -187,7 +187,7 @@ describe("product api interaction with listing", () => {
             } as TalerMerchantApi.ProductDetail,
           });
 
-          api.management.updateProduct(undefined, "1234", {
+          api.instance.updateProduct(undefined, "1234", {
             price: "ARS:13",
           } as any);
         },
@@ -267,7 +267,7 @@ describe("product api interaction with listing", () => {
               price: "ARS:12",
             } as TalerMerchantApi.ProductDetail,
           });
-          api.management.deleteProduct(undefined, "2345");
+          api.instance.deleteProduct(undefined, "2345");
         },
         ({ query, api }) => {
           expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -337,7 +337,7 @@ describe("product api interaction with details", () => {
             } as TalerMerchantApi.ProductDetail,
           });
 
-          api.management.updateProduct(undefined, "12", {
+          api.instance.updateProduct(undefined, "12", {
             description: "other description",
           } as any);
         },
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts 
b/packages/merchant-backoffice-ui/src/hooks/product.ts
index 6721136a5..cfbd4a653 100644
--- a/packages/merchant-backoffice-ui/src/hooks/product.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/product.ts
@@ -40,14 +40,14 @@ export function revalidateInstanceProducts() {
 }
 export function useInstanceProducts() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   const [offset, setOffset] = useState<number | undefined>();
 
   async function fetcher([token, bid]: [AccessToken, number]) {
-    const list = await management.listProducts(token, {
+    const list = await instance.listProducts(token, {
       limit: PAGE_SIZE,
-      offset: String(bid),
+      offset: bid === undefined ? undefined: String(bid),
       order: "dec",
     });
     if (list.type !== "ok") {
@@ -55,7 +55,7 @@ export function useInstanceProducts() {
     }
     const all: Array<ProductWithId | undefined> = await Promise.all(
       list.body.products.map(async (c) => {
-        const r = await management.getProductDetails(token, c.product_id);
+        const r = await instance.getProductDetails(token, c.product_id);
         if (r.type === "fail") {
           return undefined;
         }
@@ -89,10 +89,10 @@ export function revalidateProductDetails() {
 }
 export function useProductDetails(productId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([pid, token]: [string, AccessToken]) {
-    return await management.getProductDetails(token, pid);
+    return await instance.getProductDetails(token, pid);
   }
 
   const { data, error } = useSWR<
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts 
b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index 10e480b01..dbea93fdf 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -39,12 +39,12 @@ export function revalidateInstanceTemplates() {
 }
 export function useInstanceTemplates() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   const [offset, setOffset] = useState<string | undefined>();
 
   async function fetcher([token, bid]: [AccessToken, string]) {
-    return await management.listTemplates(token, {
+    return await instance.listTemplates(token, {
       limit: PAGE_SIZE,
       offset: bid,
       order: "dec",
@@ -73,10 +73,10 @@ export function revalidateProductDetails() {
 }
 export function useTemplateDetails(templateId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([tid, token]: [string, AccessToken]) {
-    return await management.getTemplateDetails(token, tid);
+    return await instance.getTemplateDetails(token, tid);
   }
 
   const { data, error } = useSWR<
diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts 
b/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts
index b424e9686..d0865d236 100644
--- a/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/transfer.test.ts
@@ -86,7 +86,7 @@ describe("transfer api interaction with listing", () => {
             },
           });
 
-          api.management.informWireTransfer(undefined, {
+          api.instance.informWireTransfer(undefined, {
             wtid: "3",
             credit_amount: "EUR:1" as AmountString,
             exchange_url: "exchange.url",
diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts 
b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
index 2810a4cba..44068f52d 100644
--- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
@@ -43,12 +43,12 @@ export function useInstanceTransfers(
   updatePosition: (id: string | undefined) => void = (() => { }),
 ) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   // const [offset, setOffset] = useState<string | undefined>(args?.position);
 
   async function fetcher([token, o, p, v]: [AccessToken, string, string, 
boolean]) {
-    return await management.listWireTransfers(token, {
+    return await instance.listWireTransfers(token, {
       paytoURI: p,
       verified: v,
       limit: PAGE_SIZE,
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts 
b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
index 5e2e08bcc..c69db6e80 100644
--- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
@@ -37,12 +37,12 @@ export function revalidateInstanceWebhooks() {
 }
 export function useInstanceWebhooks() {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   const [offset, setOffset] = useState<string | undefined>();
 
   async function fetcher([token, bid]: [AccessToken, string]) {
-    return await management.listWebhooks(token, {
+    return await instance.listWebhooks(token, {
       limit: 5,
       offset: bid,
       order: "dec",
@@ -104,10 +104,10 @@ export function revalidateWebhookDetails() {
 }
 export function useWebhookDetails(webhookId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { management } } = useMerchantApiContext();
+  const { lib: { instance } } = useMerchantApiContext();
 
   async function fetcher([hookId, token]: [string, AccessToken]) {
-    return await management.getWebhookDetails(token, hookId);
+    return await instance.getWebhookDetails(token, hookId);
   }
 
   const { data, error } = useSWR<
diff --git 
a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx
index 39fdb6bdc..54d947e14 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx
@@ -19,9 +19,9 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { h, VNode, FunctionalComponent } from "preact";
-import { CreatePage as TestedComponent } from "./CreatePage.js";
 import { MerchantApiProviderTesting } from "@gnu-taler/web-util/browser";
+import { FunctionalComponent, h } from "preact";
+import { CreatePage as TestedComponent } from "./CreatePage.js";
 
 export default {
   title: "Pages/Instance/Create",
@@ -40,6 +40,7 @@ function createExample<Props>(
     <MerchantApiProviderTesting
       value={{
         cancelRequest: () => {},
+        changeBackend: () => {},
         config: {
           currency: "ARS",
           version: "1",
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
index 431015d6f..8ee8608a3 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -54,7 +54,7 @@ export default function Create({ onBack, onConfirm, forceId 
}: Props): VNode {
         ) => {
           if (state.status !== "loggedIn") return;
           try {
-            await lib.management.createInstance(state.token, d);
+            await lib.instance.createInstance(state.token, d);
             if (d.auth.token) {
               //if auth has been updated, request a new access token
               const result = await lib.authenticate.createAccessTokenBearer(
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx
index 8166dc739..d4258058b 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx
@@ -40,6 +40,7 @@ function createExample<Props>(
     <MerchantApiProviderTesting
       value={{
         cancelRequest: () => {},
+        changeBackend: () => {},
         config: {
           currency: "ARS",
           version: "1",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
index a03a2659b..923c095d3 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
@@ -20,7 +20,10 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import {
+  useMerchantApiContext,
+  useTranslationContext,
+} from "@gnu-taler/web-util/browser";
 import { h, VNode } from "preact";
 import { StateUpdater, useEffect, useState } from "preact/hooks";
 import { useSessionContext } from "../../../context/session.js";
@@ -149,7 +152,8 @@ function Table({
   onPurge,
 }: TableProps): VNode {
   const { i18n } = useTranslationContext();
-  const { impersonate } = useSessionContext()
+  const { lib } = useMerchantApiContext();
+  const { impersonate } = useSessionContext();
   return (
     <div class="table-container">
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -198,10 +202,16 @@ function Table({
                 </td>
                 <td>
                   <a
-                    href={`#/orders?instance=${i.id}`}
-                    onClick={(e) => {
-                      impersonate({instance: i.id});
+                    href={`#/orders`}
+                    onClick={async (e) => {
                       e.preventDefault();
+                      const newInstanceApi = lib.subInstanceApi(i.id);
+                      //not checking /config since this comes from instance 
list
+                      impersonate({
+                        instance: i.id,
+                        baseUrl: new URL(newInstanceApi.instance.baseUrl),
+                        token: undefined,
+                      });
                     }}
                   >
                     {i.id}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
index f26ff8935..7bf64cdbb 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
@@ -91,7 +91,7 @@ export default function Instances({
               return;
             }
             try {
-              await lib.management.deleteInstance(state.token, deleting.id);
+              await lib.instance.deleteInstance(state.token, deleting.id);
               // pushNotification({message: 'delete_success', type: 'SUCCESS' 
})
               setNotif({
                 message: i18n.str`Instance "${deleting.name}" (ID: 
${deleting.id}) has been deleted`,
@@ -118,7 +118,7 @@ export default function Instances({
               return;
             }
             try {
-              await lib.management.deleteInstance(state.token, purging.id, { 
purge: true });
+              await lib.instance.deleteInstance(state.token, purging.id, { 
purge: true });
               setNotif({
                 message: i18n.str`Instance '${purging.name}' (ID: 
${purging.id}) has been disabled`,
                 type: "SUCCESS",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
index 0ce126b76..3d27b9a1a 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
@@ -46,7 +46,7 @@ export default function CreateValidator({ onConfirm, onBack 
}: Props): VNode {
       <CreatePage
         onBack={onBack}
         onCreate={(request: Entity) => {
-          return api.management.addBankAccount(state.token, request)
+          return api.instance.addBankAccount(state.token, request)
             .then(() => {
               onConfirm()
             })
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx
index 50cf0fe70..4ee68cd80 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/ListPage.tsx
@@ -24,12 +24,12 @@ import { h, VNode } from "preact";
 import { CardTable } from "./Table.js";
 
 export interface Props {
-  devices: TalerMerchantApi.BankAccountEntry[];
-  onLoadMoreBefore?: () => void;
-  onLoadMoreAfter?: () => void;
+  devices: TalerMerchantApi.BankAccountSummaryEntry[];
+  // onLoadMoreBefore?: () => void;
+  // onLoadMoreAfter?: () => void;
   onCreate: () => void;
-  onDelete: (e: TalerMerchantApi.BankAccountEntry) => void;
-  onSelect: (e: TalerMerchantApi.BankAccountEntry) => void;
+  onDelete: (e: TalerMerchantApi.BankAccountSummaryEntry) => void;
+  onSelect: (e: TalerMerchantApi.BankAccountSummaryEntry) => void;
 }
 
 export function ListPage({
@@ -37,8 +37,8 @@ export function ListPage({
   onCreate,
   onDelete,
   onSelect,
-  onLoadMoreBefore,
-  onLoadMoreAfter,
+  // onLoadMoreBefore,
+  // onLoadMoreAfter,
 }: Props): VNode {
 
   return (
@@ -51,10 +51,10 @@ export function ListPage({
         onCreate={onCreate}
         onDelete={onDelete}
         onSelect={onSelect}
-        onLoadMoreBefore={onLoadMoreBefore}
-        hasMoreBefore={!onLoadMoreBefore}
-        onLoadMoreAfter={onLoadMoreAfter}
-        hasMoreAfter={!onLoadMoreAfter}
+        // onLoadMoreBefore={onLoadMoreBefore}
+        // hasMoreBefore={!onLoadMoreBefore}
+        // onLoadMoreAfter={onLoadMoreAfter}
+        // hasMoreAfter={!onLoadMoreAfter}
       />
     </section>
   );
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx
index 690e3a2fc..efe484402 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx
@@ -24,17 +24,13 @@ import { useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { Fragment, h, VNode } from "preact";
 import { StateUpdater, useState } from "preact/hooks";
 
-type Entity = TalerMerchantApi.BankAccountEntry;
+type Entity = TalerMerchantApi.BankAccountSummaryEntry;
 
 interface Props {
   accounts: Entity[];
   onDelete: (e: Entity) => void;
   onSelect: (e: Entity) => void;
   onCreate: () => void;
-  onLoadMoreBefore?: () => void;
-  hasMoreBefore?: boolean;
-  hasMoreAfter?: boolean;
-  onLoadMoreAfter?: () => void;
 }
 
 export function CardTable({
@@ -42,10 +38,6 @@ export function CardTable({
   onCreate,
   onDelete,
   onSelect,
-  onLoadMoreAfter,
-  onLoadMoreBefore,
-  hasMoreAfter,
-  hasMoreBefore,
 }: Props): VNode {
   const [rowSelection, rowSelectionHandler] = useState<string[]>([]);
 
@@ -83,10 +75,6 @@ export function CardTable({
                 onSelect={onSelect}
                 rowSelection={rowSelection}
                 rowSelectionHandler={rowSelectionHandler}
-                onLoadMoreAfter={onLoadMoreAfter}
-                onLoadMoreBefore={onLoadMoreBefore}
-                hasMoreAfter={hasMoreAfter}
-                hasMoreBefore={hasMoreBefore}
               />
             ) : (
               <EmptyTable />
@@ -103,20 +91,12 @@ interface TableProps {
   onDelete: (e: Entity) => void;
   onSelect: (e: Entity) => void;
   rowSelectionHandler: StateUpdater<string[]>;
-  onLoadMoreBefore?: () => void;
-  hasMoreBefore?: boolean;
-  hasMoreAfter?: boolean;
-  onLoadMoreAfter?: () => void;
 }
 
 function Table({
   accounts,
-  onLoadMoreAfter,
   onDelete,
   onSelect,
-  onLoadMoreBefore,
-  hasMoreAfter,
-  hasMoreBefore,
 }: TableProps): VNode {
   const { i18n } = useTranslationContext();
   const emptyList: Record<PaytoType | "unknown", { parsed: PaytoUri, acc: 
Entity }[]> = { "bitcoin": [], "x-taler-bank": [], "iban": [], "unknown": [], }
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
index a9454cd07..ccfab3c45 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
@@ -81,16 +81,16 @@ export default function ListOtpDevices({
       }
       <ListPage
         devices={result.body}
-        onLoadMoreBefore={
-          result.isFirstPage ? undefined: result.loadFirst
-        }
-        onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext}
+        // onLoadMoreBefore={
+        //   result.isFirstPage ? undefined: result.loadFirst
+        // }
+        // onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext}
         onCreate={onCreate}
         onSelect={(e) => {
           onSelect(e.h_wire);
         }}
-        onDelete={(e: TalerMerchantApi.BankAccountEntry) => {
-          return api.management.deleteBankAccount(state.token, e.h_wire)
+        onDelete={(e: TalerMerchantApi.BankAccountSummaryEntry) => {
+          return api.instance.deleteBankAccount(state.token, e.h_wire)
             .then(() =>
               setNotif({
                 message: i18n.str`bank account delete successfully`,
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
index 97610e96b..6b8af50a9 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
@@ -80,7 +80,7 @@ export default function UpdateValidator({
         account={{ ...result.body, id: bid }}
         onBack={onBack}
         onUpdate={(data) => {
-          return api.management.updateBankAccount(state.token, bid, data)
+          return api.instance.updateBankAccount(state.token, bid, data)
             .then(onConfirm)
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
index bb1ee944b..76e3bf878 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
@@ -77,7 +77,7 @@ export default function Detail({
               return
             }
             try {
-              await lib.management.deleteCurrentInstance(state.token);
+              await lib.instance.deleteCurrentInstance(state.token);
               onDelete();
             } catch (error) {
               //FIXME: show message error
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx
index 6914b7432..42cb1cb02 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/stories.tsx
@@ -40,6 +40,7 @@ function createExample<Props>(
     <MerchantApiProviderTesting
       value={{
         cancelRequest: () => { },
+        changeBackend: () => { },
         config: {
           currency: "ARS",
           version: "1",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
index f612389fe..849711df6 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
@@ -94,7 +94,7 @@ export default function OrderCreate({
       <CreatePage
         onBack={onBack}
         onCreate={(request: TalerMerchantApi.PostOrderRequest) => {
-          lib.management.createOrder(state.token, request)
+          lib.instance.createOrder(state.token, request)
             .then((r) => {
               if (r.type === "ok") {
                 return onConfirm(r.body.order_id)
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
index 4ed78b002..4afc40285 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
@@ -25,7 +25,7 @@ import {
   TalerMerchantApi,
   stringifyRefundUri,
 } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { format, formatDistance } from "date-fns";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -38,7 +38,6 @@ import { InputGroup } from 
"../../../../components/form/InputGroup.js";
 import { InputLocation } from "../../../../components/form/InputLocation.js";
 import { TextField } from "../../../../components/form/TextField.js";
 import { ProductList } from "../../../../components/product/ProductList.js";
-import { useSessionContext } from "../../../../context/session.js";
 import {
   datetimeFormatForSettings,
   usePreference,
@@ -427,12 +426,10 @@ function PaidPage({
   });
 
   const [value, valueHandler] = useState<Partial<Paid>>(order);
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
 
   const refundurl = stringifyRefundUri({
-    merchantBaseUrl: backendUrl,
+    merchantBaseUrl: backendUrl.href,
     orderId: order.contract_terms.order_id,
   });
   const refundable =
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
index b232a146b..4785c795d 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
@@ -84,7 +84,7 @@ export default function Update({ oid, onBack }: Props): VNode 
{
           if (state.status !== "loggedIn") {
             return;
           }
-          api.management
+          api.instance
             .addRefund(state.token, id, value)
             .then(() =>
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
index 165ced3dc..217eb998a 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
@@ -110,7 +110,7 @@ export default function OrderList({ onCreate, onSelect }: 
Props): VNode {
 
       <JumpToElementById
         testIfExist={async (order) => {
-          const resp = await lib.management.getOrderDetails(state.token, 
order);
+          const resp = await lib.instance.getOrderDetails(state.token, order);
           return resp.type === "ok";
         }}
         onSelect={onSelect}
@@ -135,7 +135,7 @@ export default function OrderList({ onCreate, onSelect }: 
Props): VNode {
         jumpToDate={filter.date}
         onSelectDate={setNewDate}
         onCopyURL={async (id) => {
-          const resp = await lib.management.getOrderDetails(state.token, id);
+          const resp = await lib.instance.getOrderDetails(state.token, id);
           if (resp.type === "ok") {
             if (resp.body.order_status === "unpaid") {
               copyToClipboard(resp.body.taler_pay_uri);
@@ -161,7 +161,7 @@ export default function OrderList({ onCreate, onSelect }: 
Props): VNode {
           id={orderToBeRefunded.order_id}
           onCancel={() => setOrderToBeRefunded(undefined)}
           onConfirm={(value) => {
-            lib.management
+            lib.instance
               .addRefund(state.token, orderToBeRefunded.order_id, value)
               .then(() =>
                 setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
index b1b4a0cf7..982132057 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
@@ -15,7 +15,7 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { QR } from "../../../../components/exception/QR.js";
 import { CreatedSuccessfully as Template } from 
"../../../../components/notifications/CreatedSuccessfully.js";
@@ -33,11 +33,9 @@ export function CreatedSuccessfully({
   onConfirm,
 }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
   const { state } = useSessionContext();
-  const issuer = backendUrl;
+  const issuer = backendUrl.href;
   const qrText = 
`otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key}`;
   const qrTextSafe = 
`otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0,
 6)}...`;
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
index 6ad1295ed..864190c9f 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
@@ -52,7 +52,7 @@ export default function CreateValidator({ onConfirm, onBack 
}: Props): VNode {
       <CreatePage
         onBack={onBack}
         onCreate={(request: Entity) => {
-          return api.management.addOtpDevice(state.token, request)
+          return api.instance.addOtpDevice(state.token, request)
             .then((d) => {
               setCreated(request)
             })
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
index 6b3eded17..324207f59 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
@@ -85,7 +85,7 @@ export default function ListOtpDevices({ onCreate, onSelect 
}: Props): VNode {
           onSelect(e.otp_device_id);
         }}
         onDelete={(e: TalerMerchantApi.OtpDeviceEntry) => {
-          return lib.management
+          return lib.instance
             .deleteOtpDevice(state.token, e.otp_device_id)
             .then(() =>
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
index 4dc3ec67f..5e34e4c8a 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
@@ -98,7 +98,7 @@ export default function UpdateValidator({
         }}
         onBack={onBack}
         onUpdate={async (newInfo) => {
-          return lib.management
+          return lib.instance
             .updateOtpDevice(state.token, vid, newInfo)
             .then((d) => {
               if (d.type === "ok") {
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
index 6cb083025..e1e3c846a 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
@@ -45,7 +45,7 @@ export default function CreateProduct({ onConfirm, onBack }: 
Props): VNode {
       <CreatePage
         onBack={onBack}
         onCreate={(request: TalerMerchantApi.ProductAddDetail) => {
-          return lib.management.addProduct(state.token, request)
+          return lib.instance.addProduct(state.token, request)
             .then(() => onConfirm())
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
index 73c221662..dfd633150 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
@@ -81,7 +81,7 @@ export default function ProductList({
 
       <JumpToElementById
         testIfExist={async (id) => {
-          const resp = await lib.management.getProductDetails(state.token, id);
+          const resp = await lib.instance.getProductDetails(state.token, id);
           return resp.type === "ok";
         }}
         onSelect={onSelect}
@@ -94,7 +94,7 @@ export default function ProductList({
         onCreate={onCreate}
         onUpdate={async (id, prod) => {
           try {
-            await lib.management.updateProduct(state.token, id, prod);
+            await lib.instance.updateProduct(state.token, id, prod);
             setNotif({
               message: i18n.str`product updated successfully`,
               type: "SUCCESS",
@@ -123,7 +123,7 @@ export default function ProductList({
           onCancel={() => setDeleting(null)}
           onConfirm={async (): Promise<void> => {
             try {
-              await lib.management.deleteProduct(state.token, deleting.id);
+              await lib.instance.deleteProduct(state.token, deleting.id);
               setNotif({
                 message: i18n.str`Product "${deleting.description}" (ID: 
${deleting.id}) has been deleted`,
                 type: "SUCCESS",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
index 08b169610..06f813b14 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
@@ -79,7 +79,7 @@ export default function UpdateProduct({
         product={{ ...result.body, product_id: pid }}
         onBack={onBack}
         onUpdate={(data) => {
-          return lib.management.updateProduct(state.token, pid, data)
+          return lib.instance.updateProduct(state.token, pid, data)
             .then(onConfirm)
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 82c0d0e53..2ba637f44 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -28,6 +28,7 @@ import {
   assertUnreachable,
 } from "@gnu-taler/taler-util";
 import {
+  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
@@ -44,7 +45,6 @@ import { InputNumber } from 
"../../../../components/form/InputNumber.js";
 import { InputSearchOnList } from 
"../../../../components/form/InputSearchOnList.js";
 import { InputTab } from "../../../../components/form/InputTab.js";
 import { InputWithAddon } from "../../../../components/form/InputWithAddon.js";
-import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
 
 enum Steps {
@@ -73,9 +73,7 @@ interface Props {
 
 export function CreatePage({ onCreate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
   const devices = useInstanceOtpDevices();
 
   const [state, setState] = useState<Partial<Entity>>({
@@ -201,7 +199,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
             >
               <InputWithAddon<Entity>
                 name="id"
-                help={new URL(`templates/${state.id ?? ""}`, backendUrl).href}
+                help={new URL(`templates/${state.id ?? ""}`, 
backendUrl.href).href}
                 label={i18n.str`Identifier`}
                 tooltip={i18n.str`Name of the template in URLs.`}
               />
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
index d23afb609..f71ca4794 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
@@ -46,7 +46,7 @@ export default function CreateTransfer({ onConfirm, onBack }: 
Props): VNode {
       <CreatePage
         onBack={onBack}
         onCreate={(request: TalerMerchantApi.TemplateAddDetails) => {
-          return lib.management.addTemplate(state.token, request)
+          return lib.instance.addTemplate(state.token, request)
             .then(() => onConfirm())
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
index 23bc95943..f9ab6678b 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
@@ -85,7 +85,7 @@ export default function ListTemplates({
 
       <JumpToElementById
         testIfExist={async (id) => {
-          const resp = await lib.management.getTemplateDetails(state.token, id)
+          const resp = await lib.instance.getTemplateDetails(state.token, id)
           return resp.type === "ok"
         }}
         onSelect={onSelect}
@@ -124,7 +124,7 @@ export default function ListTemplates({
           onCancel={() => setDeleting(null)}
           onConfirm={async (): Promise<void> => {
             try {
-              await lib.management.deleteTemplate(state.token, 
deleting.template_id);
+              await lib.instance.deleteTemplate(state.token, 
deleting.template_id);
               setNotif({
                 message: i18n.str`Template "${deleting.template_description}" 
(ID: ${deleting.template_id}) has been deleted`,
                 type: "SUCCESS",
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
index d48e5e956..0749f45d3 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
@@ -33,7 +33,6 @@ import {
 } from "../../../../components/form/FormProvider.js";
 import { Input } from "../../../../components/form/Input.js";
 import { InputCurrency } from "../../../../components/form/InputCurrency.js";
-import { useSessionContext } from "../../../../context/session.js";
 
 type Entity = TalerMerchantApi.UsingTemplateDetails;
 
@@ -45,10 +44,7 @@ interface Props {
 
 export function QrPage({ contract, id: templateId, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
-  const { config } = useMerchantApiContext();
+  const { config, url: backendUrl } = useMerchantApiContext();
 
   const [state, setState] = useState<Partial<Entity>>({
     amount: contract.amount,
@@ -73,7 +69,7 @@ export function QrPage({ contract, id: templateId, onBack }: 
Props): VNode {
     templateParams.summary = state.summary ?? "";
   }
 
-  const merchantBaseUrl = backendUrl;
+  const merchantBaseUrl = backendUrl.href;
 
   const payTemplateUri = stringifyPayTemplateUri({
     merchantBaseUrl,
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
index cf1c13fc4..e1493a870 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
@@ -27,7 +27,7 @@ import {
   TalerMerchantApi,
   assertUnreachable
 } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
@@ -41,7 +41,6 @@ import { InputDuration } from 
"../../../../components/form/InputDuration.js";
 import { InputNumber } from "../../../../components/form/InputNumber.js";
 import { InputSearchOnList } from 
"../../../../components/form/InputSearchOnList.js";
 import { InputTab } from "../../../../components/form/InputTab.js";
-import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
 
 enum Steps {
@@ -68,9 +67,7 @@ interface Props {
 
 export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const {
-    state: { backendUrl },
-  } = useSessionContext();
+  const { url: backendUrl } = useMerchantApiContext();
 
 
   const intialStep =
@@ -190,7 +187,7 @@ export function UpdatePage({ template, onUpdate, onBack }: 
Props): VNode {
               <div class="level-left">
                 <div class="level-item">
                   <span class="is-size-4">
-                    {new URL(`templates/${template.otp_id}`,backendUrl).href}
+                    {new 
URL(`templates/${template.otp_id}`,backendUrl.href).href}
                   </span>
                 </div>
               </div>
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
index 5fc8bee93..2c0c358e2 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
@@ -82,7 +82,7 @@ export default function UpdateTemplate({
         template={result.body}
         onBack={onBack}
         onUpdate={(data) => {
-          return lib.management.updateTemplate(state.token, tid, data)
+          return lib.instance.updateTemplate(state.token, tid, data)
             .then(onConfirm)
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
index d631cef96..46d4da8d7 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
@@ -83,7 +83,7 @@ export default function TemplateUsePage({
           request: TalerMerchantApi.UsingTemplateDetails,
         ) => {
 
-          return lib.management.useTemplateCreateOrder(tid, request)
+          return lib.instance.useTemplateCreateOrder(tid, request)
             .then((res) => {
               if (res.type === "ok") {
                 onOrderCreated(res.body.order_id)
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
index 768e21325..cc8f7f9e8 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -70,7 +70,7 @@ export default function Token({
         hasToken={hasToken}
         onClearToken={async (currentToken): Promise<void> => {
           try {
-            await 
lib.management.updateCurrentInstanceAuthentication(currentToken, {
+            await 
lib.instance.updateCurrentInstanceAuthentication(currentToken, {
               method: "external",
             })
             onChange();
@@ -86,7 +86,7 @@ export default function Token({
         }}
         onNewToken={async (currentToken, newToken): Promise<void> => {
           try {
-            await 
lib.management.updateCurrentInstanceAuthentication(currentToken, {
+            await 
lib.instance.updateCurrentInstanceAuthentication(currentToken, {
               token: newToken,
               method: "token"
             })
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
index 35389f5f5..4a92c1178 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
@@ -56,7 +56,7 @@ export default function CreateTransfer({ onConfirm, onBack }: 
Props): VNode {
         onBack={onBack}
         accounts={accounts}
         onCreate={(request: TalerMerchantApi.TransferInformation) => {
-          return lib.management
+          return lib.instance
             .informWireTransfer(state.token, request)
             .then(() => onConfirm())
             .catch((error) => {
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
index b5319bc2d..4afc400f8 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
@@ -45,15 +45,15 @@ export interface Props {
 
 export default function Update(props: Props): VNode {
   const { lib } = useMerchantApiContext();
-  const updateInstance = 
lib.management.updateCurrentInstance.bind(lib.management)
+  const updateInstance = lib.instance.updateCurrentInstance.bind(lib.instance)
   const result = useInstanceDetails();
   return CommonUpdate(props, result, updateInstance,);
 }
 
 export function AdminUpdate(props: Props & { instanceId: string }): VNode {
   const { lib } = useMerchantApiContext();
-  const t = lib.instance(props.instanceId)
-  const updateInstance = 
lib.instance(props.instanceId).updateCurrentInstance.bind(t)
+  const t = lib.subInstanceApi(props.instanceId).instance;
+  const updateInstance = t.updateCurrentInstance.bind(t)
   const result = useManagedInstanceDetails(props.instanceId);
   return CommonUpdate(props, result, updateInstance,);
 }
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
index 50c431079..e4d260b04 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
@@ -46,7 +46,7 @@ export default function CreateWebhook({ onConfirm, onBack }: 
Props): VNode {
       <CreatePage
         onBack={onBack}
         onCreate={(request: TalerMerchantApi.WebhookAddDetails) => {
-          return lib.management.addWebhook(state.token, request)
+          return lib.instance.addWebhook(state.token, request)
             .then(() => onConfirm())
             .catch((error) => {
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
index 102aef96e..6c68bc973 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
@@ -84,7 +84,7 @@ export default function ListWebhooks({ onCreate, onSelect }: 
Props): VNode {
           onSelect(e.webhook_id);
         }}
         onDelete={(e: TalerMerchantApi.WebhookEntry) => {
-          return lib.management
+          return lib.instance
             .deleteWebhook(state.token, e.webhook_id)
             .then(() =>
               setNotif({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
index 262e5bba4..1253cd9a2 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
@@ -82,7 +82,7 @@ export default function UpdateWebhook({
         webhook={{ ...result.body, id: tid }}
         onBack={onBack}
         onUpdate={(data) => {
-          return lib.management.updateWebhook(state.token, tid, data)
+          return lib.instance.updateWebhook(state.token, tid, data)
             .then(onConfirm)
             .catch((error) => {
               setNotif({
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index 86ec9a9e6..30b5c37bd 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -19,9 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import {
-  HttpStatusCode
-} from "@gnu-taler/taler-util";
+import { HttpStatusCode } from "@gnu-taler/taler-util";
 import {
   useMerchantApiContext,
   useTranslationContext,
@@ -29,12 +27,10 @@ import {
 import { ComponentChildren, Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../components/menu/index.js";
-import {
-  useSessionContext
-} from "../../context/session.js";
+import { useSessionContext } from "../../context/session.js";
 import { Notification } from "../../utils/types.js";
 
-interface Props { }
+interface Props {}
 
 const tokenRequest = {
   scope: "write",
@@ -47,18 +43,30 @@ const tokenRequest = {
 export function LoginPage(_p: Props): VNode {
   const [token, setToken] = useState("");
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { state, logIn } = useSessionContext();
+  const { state, logIn, impersonate } = useSessionContext();
   const { lib } = useMerchantApiContext();
 
   const { i18n } = useTranslationContext();
 
   async function doImpersonateImpl(instanceId: string) {
-    const result = await lib
-      .impersonate(instanceId)
-      .createAccessTokenBearer(token, tokenRequest);
+    const newInstanceApi = lib.subInstanceApi(instanceId);
+    const cfg = await newInstanceApi.instance.getConfig();
+    if (cfg.type !== "ok") {
+      setNotif({
+        message: "Could not load the configuration of this instance.",
+        description: newInstanceApi.instance.baseUrl,
+        type: "ERROR",
+      });
+      return;
+    }
+    const result = await newInstanceApi.authenticate.createAccessTokenBearer(
+      token,
+      tokenRequest,
+    );
+    
     if (result.type === "ok") {
       const { token } = result.body;
-      logIn({ token });
+      impersonate({ instance: instanceId, baseUrl: new 
URL(newInstanceApi.instance.baseUrl), token });
       return;
     } else {
       switch (result.case) {
@@ -126,7 +134,8 @@ export function LoginPage(_p: Props): VNode {
             >
               <p>
                 <i18n.Translate>
-                  Need the access token for the instance 
<b>"{state.instance}"</b>
+                  Need the access token for the instance{" "}
+                  <b>"{state.instance}"</b>
                 </i18n.Translate>
               </p>
               <div class="field is-horizontal">
@@ -190,7 +199,9 @@ export function LoginPage(_p: Props): VNode {
               class="modal-card-body"
               style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
             >
-              <i18n.Translate>Please enter your access token for 
<b>"{state.instance}"</b>.</i18n.Translate>
+              <i18n.Translate>
+                Please enter your access token for <b>"{state.instance}"</b>.
+              </i18n.Translate>
 
               <div class="field is-horizontal">
                 <div class="field-label is-normal">
diff --git a/packages/taler-harness/src/index.ts 
b/packages/taler-harness/src/index.ts
index 727c3b674..5f2708b85 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -653,6 +653,12 @@ deploymentCli
 
 
     const bc = await bank.getConfig()
+    if (bc.type === "fail") {
+      logger.error(
+        `couldn't get bank config. ${bc.detail.hint}`,
+      );
+      return;
+    }
     if (!bank.isCompatible(bc.body.version)) {
       logger.error(
         `bank server version is not compatible: ${bc.body.version}, client 
version: ${bank.PROTOCOL_VERSION}`,
@@ -660,6 +666,12 @@ deploymentCli
       return;
     }
     const mc = await merchantManager.getConfig()
+    if (mc.type === "fail") {
+      logger.error(
+        `couldn't get merchant config. ${mc.detail.hint}`,
+      );
+      return;
+    }
     if (!merchantManager.isCompatible(mc.body.version)) {
       logger.error(
         `merchant server version is not compatible: ${mc.body.version}, client 
version: ${merchantManager.PROTOCOL_VERSION}`,
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index b89ac8af6..59698a68b 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -128,6 +128,8 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForCoreBankConfig());
+      case HttpStatusCode.NotFound:
+        return opKnownHttpFailure(resp.status, resp);
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -146,9 +148,9 @@ export class TalerCoreBankHttpClient {
     body: TalerCorebankApi.RegisterAccountRequest,
   ) {
     const url = new URL(`accounts`, this.baseUrl);
-    const headers: Record<string, string> = {}
+    const headers: Record<string, string> = {};
     if (auth) {
-      headers.Authorization = makeBearerTokenAuthHeader(auth)
+      headers.Authorization = makeBearerTokenAuthHeader(auth);
     }
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
@@ -936,7 +938,7 @@ export class TalerCoreBankHttpClient {
       );
     }
     if (params.date) {
-      const {t_s: seconds} = AbsoluteTime.toProtocolTimestamp(params.date)
+      const { t_s: seconds } = AbsoluteTime.toProtocolTimestamp(params.date);
       if (seconds !== "never") {
         url.searchParams.set("date_s", String(seconds));
       }
diff --git a/packages/taler-util/src/http-client/exchange.ts 
b/packages/taler-util/src/http-client/exchange.ts
index befde4d20..ea7f44cf9 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -71,6 +71,8 @@ export class TalerExchangeHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForExchangeConfig());
+      case HttpStatusCode.NotFound:
+        return opKnownHttpFailure(resp.status, resp);
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
diff --git a/packages/taler-util/src/http-client/merchant.ts 
b/packages/taler-util/src/http-client/merchant.ts
index 7d80cacb5..cfe3155d1 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -127,6 +127,8 @@ export class TalerMerchantInstanceHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForMerchantConfig());
+      case HttpStatusCode.NotFound:
+        return opKnownHttpFailure(resp.status, resp);
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -1677,7 +1679,7 @@ export class TalerMerchantInstanceHttpClient {
     });
 
     switch (resp.status) {
-      case HttpStatusCode.NoContent:
+      case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForWebhookSummaryResponse());
       case HttpStatusCode.Unauthorized: // FIXME: missing in docs
         return opKnownHttpFailure(resp.status, resp);
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 8037b5a16..dd2161deb 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -524,17 +524,24 @@ export const codecForAccountAddResponse =
 export const codecForAccountsSummaryResponse =
   (): Codec<TalerMerchantApi.AccountsSummaryResponse> =>
     buildCodecForObject<TalerMerchantApi.AccountsSummaryResponse>()
-      .property("accounts", codecForList(codecForBankAccountEntry()))
+      .property("accounts", codecForList(codecForBankAccountSummaryEntry()))
       .build("TalerMerchantApi.AccountsSummaryResponse");
 
+export const codecForBankAccountSummaryEntry =
+  (): Codec<TalerMerchantApi.BankAccountSummaryEntry> =>
+    buildCodecForObject<TalerMerchantApi.BankAccountSummaryEntry>()
+      .property("payto_uri", codecForPaytoString())
+      .property("h_wire", codecForString())
+      .build("TalerMerchantApi.BankAccountSummaryEntry");
+
 export const codecForBankAccountEntry =
   (): Codec<TalerMerchantApi.BankAccountEntry> =>
     buildCodecForObject<TalerMerchantApi.BankAccountEntry>()
       .property("payto_uri", codecForPaytoString())
       .property("h_wire", codecForString())
       .property("salt", codecForString())
-      .property("credit_facade_url", codecForURL())
-      .property("active", codecForBoolean())
+      .property("credit_facade_url", codecOptional(codecForURL()))
+      .property("active", codecOptional(codecForBoolean()))
       .build("TalerMerchantApi.BankAccountEntry");
 
 export const codecForInventorySummaryResponse =
@@ -3772,7 +3779,14 @@ export namespace TalerMerchantApi {
 
   export interface AccountsSummaryResponse {
     // List of accounts that are known for the instance.
-    accounts: BankAccountEntry[];
+    accounts: BankAccountSummaryEntry[];
+  }
+  export interface BankAccountSummaryEntry {
+    // payto:// URI of the account.
+    payto_uri: PaytoString;
+
+    // Hash over the wire details (including over the salt).
+    h_wire: HashCode;
   }
   export interface BankAccountEntry {
     // payto:// URI of the account.
@@ -3790,7 +3804,7 @@ export namespace TalerMerchantApi {
 
     // true if this account is active,
     // false if it is historic.
-    active: boolean;
+    active?: boolean;
   }
 
   export interface ProductAddDetail {
diff --git a/packages/taler-util/src/whatwg-url.ts 
b/packages/taler-util/src/whatwg-url.ts
index 991528ae6..13abf5397 100644
--- a/packages/taler-util/src/whatwg-url.ts
+++ b/packages/taler-util/src/whatwg-url.ts
@@ -1908,15 +1908,22 @@ function parseURL(
 }
 
 export class URLImpl {
-  constructor(url: string, base?: string) {
+  //Include URL type for "url" and "base" params.
+  constructor(url: string | URL, base?: string | URL) {
     let parsedBase = null;
     if (base !== undefined) {
+      if (base instanceof URL) {
+        base = base.href;
+      }
       parsedBase = basicURLParse(base);
       if (parsedBase === null) {
         throw new TypeError(`Invalid base URL: ${base}`);
       }
     }
 
+    if (url instanceof URL) {
+      url = url.href;
+    }
     const parsedURL = basicURLParse(url, { baseURL: parsedBase });
     if (parsedURL === null) {
       throw new TypeError(`Invalid URL: ${url}`);
diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts 
b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts
index d59501212..3d5a105ec 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts
@@ -14,12 +14,12 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { OperationFailWithBody, OperationOk, OperationResult, TalerExchangeApi 
} from "@gnu-taler/taler-util";
+import { OperationFailWithBody, OperationOk, TalerExchangeApi } from 
"@gnu-taler/taler-util";
 import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
 import { ErrorAlert } from "../../context/alert.js";
 import { TextFieldHandler } from "../../mui/handlers.js";
-import { compose, StateViewMap } from "../../utils/index.js";
+import { StateViewMap, compose } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
 import { ConfirmView, VerifyView } from "./views.js";
 
@@ -37,6 +37,7 @@ export type State = State.Loading
 export type CheckExchangeErrors = {
   "invalid-version": string;
   "invalid-currency": string;
+  "not-found": void;
   "already-active": void;
   "invalid-protocol": void;
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts 
b/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts
index 5ae0aa8f4..4a04f762a 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts
@@ -14,15 +14,15 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { ExchangeEntryStatus, OperationFailWithBody, OperationOk, 
TalerExchangeApi, TalerExchangeHttpClient, canonicalizeBaseUrl, 
opKnownFailureWithBody } from "@gnu-taler/taler-util";
+import { ExchangeEntryStatus, TalerExchangeHttpClient, canonicalizeBaseUrl, 
opKnownFailureWithBody } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser";
 import { useCallback, useEffect, useState } from "preact/hooks";
 import { useBackendContext } from "../../context/backend.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { withSafe } from "../../mui/handlers.js";
 import { RecursiveState } from "../../utils/index.js";
 import { CheckExchangeErrors, Props, State } from "./index.js";
-import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser";
 
 function urlFromInput(str: string): URL {
   let result: URL;
@@ -83,6 +83,9 @@ export function useComponentState({ onBack, currency, 
noDebounce }: Props): Recu
          */
         const api = new TalerExchangeHttpClient(baseUrl.href, new 
BrowserFetchHttpLib() as any);
         const config = await api.getConfig()
+        if (config.type === "fail") {
+          return opKnownFailureWithBody<CheckExchangeErrors>("not-found", 
undefined)
+        }
         if (!api.isCompatible(config.body.version)) {
           return 
opKnownFailureWithBody<CheckExchangeErrors>("invalid-version", 
config.body.version)
         }
@@ -155,7 +158,7 @@ function useDebounce<T>(
   const [result, setResult] = useState<T | undefined>(undefined);
   const [error, setError] = useState<Error | undefined>(undefined);
 
-  const [handler, setHandler] = useState<any | undefined>(undefined);
+  const [handler, setHandler] = useState<number | undefined>(undefined);
 
   if (!disabled) {
     useEffect(() => {
@@ -180,7 +183,7 @@ function useDebounce<T>(
           setResult(undefined);
         }
       }, 500);
-      setHandler(h);
+      setHandler(h as unknown as number);
     }, [value, setHandler, onTrigger]);
   }
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx
index 489d7eb3b..21309fd7b 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx
@@ -17,13 +17,18 @@
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, h, VNode } from "preact";
 import { ErrorMessage } from "../../components/ErrorMessage.js";
-import { Input, LightText, SubTitle, Title, WarningBox } from 
"../../components/styled/index.js";
+import {
+  Input,
+  LightText,
+  SubTitle,
+  Title,
+  WarningBox,
+} from "../../components/styled/index.js";
 import { TermsOfService } from "../../components/TermsOfService/index.js";
 import { Button } from "../../mui/Button.js";
 import { State } from "./index.js";
 import { assertUnreachable } from "@gnu-taler/taler-util";
 
-
 export function VerifyView({
   expectedCurrency,
   onCancel,
@@ -57,40 +62,71 @@ export function VerifyView({
         {(() => {
           if (!result) return;
           if (result.type == "ok") {
-            return <LightText>
-              <i18n.Translate>
-                An exchange has been found! Review the information and click 
next
-              </i18n.Translate>
-            </LightText>
+            return (
+              <LightText>
+                <i18n.Translate>
+                  An exchange has been found! Review the information and click
+                  next
+                </i18n.Translate>
+              </LightText>
+            );
           }
           switch (result.case) {
             case "already-active": {
-              return <WarningBox>
-                <i18n.Translate>This exchange is already in your 
list.</i18n.Translate>
-              </WarningBox>
+              return (
+                <WarningBox>
+                  <i18n.Translate>
+                    This exchange is already in your list.
+                  </i18n.Translate>
+                </WarningBox>
+              );
             }
             case "invalid-protocol": {
-              return <WarningBox>
-                <i18n.Translate>Only exchange accessible through "http" and 
"https" are allowed.</i18n.Translate>
-              </WarningBox>
+              return (
+                <WarningBox>
+                  <i18n.Translate>
+                    Only exchange accessible through "http" and "https" are
+                    allowed.
+                  </i18n.Translate>
+                </WarningBox>
+              );
             }
             case "invalid-version": {
-              return <WarningBox>
-                <i18n.Translate>This exchange protocol version is not 
supported: "{result.body}".</i18n.Translate>
-              </WarningBox>
+              return (
+                <WarningBox>
+                  <i18n.Translate>
+                    This exchange protocol version is not supported: "
+                    {result.body}".
+                  </i18n.Translate>
+                </WarningBox>
+              );
             }
             case "invalid-currency": {
-              return <WarningBox>
-                <i18n.Translate>This exchange currency "{result.body}" 
doesn&apos;t match the expected currency {expectedCurrency}.</i18n.Translate>
-              </WarningBox>
+              return (
+                <WarningBox>
+                  <i18n.Translate>
+                    This exchange currency "{result.body}" doesn&apos;t match
+                    the expected currency {expectedCurrency}.
+                  </i18n.Translate>
+                </WarningBox>
+              );
+            }
+            case "not-found": {
+              return (
+                <WarningBox>
+                  <i18n.Translate>
+                    No exchange found in that URL.
+                  </i18n.Translate>
+                </WarningBox>
+              );
             }
             default: {
-              assertUnreachable(result.case)
+              assertUnreachable(result.case);
             }
           }
         })()}
         <p>
-          <Input invalid={result && result.type !== "ok"} >
+          <Input invalid={result && result.type !== "ok"}>
             <label>URL</label>
             <input
               type="text"
@@ -98,7 +134,7 @@ export function VerifyView({
               value={url.value}
               onInput={(e) => {
                 if (url.onInput) {
-                  url.onInput(e.currentTarget.value)
+                  url.onInput(e.currentTarget.value);
                 }
               }}
             />
@@ -138,10 +174,7 @@ export function VerifyView({
         </Button>
         <Button
           variant="contained"
-          disabled={
-            !result ||
-            result.type !== "ok"
-          }
+          disabled={!result || result.type !== "ok"}
           onClick={onAccept}
         >
           <i18n.Translate>Next</i18n.Translate>
@@ -149,14 +182,22 @@ export function VerifyView({
       </footer>
       <section>
         <ul>
-          {knownExchanges.map(ex => {
-            return <li><a href="#" onClick={(e) => {
-              if (url.onInput) {
-                url.onInput(ex.href)
-              }
-              e.preventDefault()
-            }}>
-              {ex.href}</a></li>
+          {knownExchanges.map((ex) => {
+            return (
+              <li key={ex.href}>
+                <a
+                  href="#"
+                  onClick={(e) => {
+                    if (url.onInput) {
+                      url.onInput(ex.href);
+                    }
+                    e.preventDefault();
+                  }}
+                >
+                  {ex.href}
+                </a>
+              </li>
+            );
           })}
         </ul>
       </section>
@@ -164,7 +205,6 @@ export function VerifyView({
   );
 }
 
-
 export function ConfirmView({
   url,
   onCancel,
@@ -186,8 +226,7 @@ export function ConfirmView({
         </div>
       </section>
 
-
-      <TermsOfService key="terms" exchangeUrl={url} >
+      <TermsOfService key="terms" exchangeUrl={url}>
         <footer>
           <Button
             key="cancel"
diff --git a/packages/web-util/src/context/activity.ts 
b/packages/web-util/src/context/activity.ts
index c38f133a1..9a16f6673 100644
--- a/packages/web-util/src/context/activity.ts
+++ b/packages/web-util/src/context/activity.ts
@@ -55,10 +55,9 @@ export interface APIClient<T, C> {
 }
 
 export interface MerchantLib {
-  management: TalerMerchantManagementHttpClient;
+  instance: TalerMerchantManagementHttpClient;
   authenticate: TalerAuthenticationHttpClient;
-  instance: (instanceId: string) => TalerMerchantInstanceHttpClient;
-  impersonate: (instanceId: string) => TalerAuthenticationHttpClient;
+  subInstanceApi: (instanceId: string) => MerchantLib;
 }
 
 export interface BankLib {
diff --git a/packages/web-util/src/context/bank-api.ts 
b/packages/web-util/src/context/bank-api.ts
index a5e5654ac..d2938f150 100644
--- a/packages/web-util/src/context/bank-api.ts
+++ b/packages/web-util/src/context/bank-api.ts
@@ -25,7 +25,7 @@ import {
   TalerCoreBankCacheEviction,
   TalerCoreBankHttpClient,
   TalerCorebankApi,
-  TalerError
+  TalerError,
 } from "@gnu-taler/taler-util";
 import {
   ComponentChildren,
@@ -56,7 +56,8 @@ export type BankContextType = {
 // @ts-expect-error default value to undefined, should it be another thing?
 const BankContext = createContext<BankContextType>(undefined);
 
-export const useBankCoreApiContext = (): BankContextType => 
useContext(BankContext);
+export const useBankCoreApiContext = (): BankContextType =>
+  useContext(BankContext);
 
 enum VersionHint {
   NONE,
@@ -65,7 +66,7 @@ enum VersionHint {
 type Evictors = {
   conversion?: CacheEvictor<TalerBankConversionCacheEviction>;
   bank?: CacheEvictor<TalerCoreBankCacheEviction>;
-}
+};
 
 type ConfigResult<T> =
   | undefined
@@ -81,13 +82,15 @@ export const BankApiProvider = ({
 }: {
   baseUrl: URL;
   children: ComponentChildren;
-  evictors?: Evictors,
+  evictors?: Evictors;
   frameOnError: FunctionComponent<{ children: ComponentChildren }>;
 }): VNode => {
-  const [checked, setChecked] = 
useState<ConfigResult<TalerCorebankApi.Config>>();
+  const [checked, setChecked] =
+    useState<ConfigResult<TalerCorebankApi.Config>>();
   const { i18n } = useTranslationContext();
 
-  const { getRemoteConfig, VERSION, lib, cancelRequest, onActivity } = 
buildBankApiClient(baseUrl, evictors);
+  const { getRemoteConfig, VERSION, lib, cancelRequest, onActivity } =
+    buildBankApiClient(baseUrl, evictors);
 
   useEffect(() => {
     getRemoteConfig()
@@ -110,7 +113,9 @@ export const BankApiProvider = ({
   }, []);
 
   if (checked === undefined) {
-    return h(frameOnError, { children: h("div", {}, "checking compatibility 
with server...") });
+    return h(frameOnError, {
+      children: h("div", {}, "checking compatibility with server..."),
+    });
   }
   if (checked.type === "error") {
     return h(frameOnError, {
@@ -141,7 +146,9 @@ export const BankApiProvider = ({
   });
 };
 
-function buildBankApiClient(url: URL, evictors: Evictors,
+function buildBankApiClient(
+  url: URL,
+  evictors: Evictors,
 ): APIClient<BankLib, TalerCorebankApi.Config> {
   const httpFetch = new BrowserFetchHttpLib({
     enableThrottling: true,
@@ -154,11 +161,7 @@ function buildBankApiClient(url: URL, evictors: Evictors,
     },
   });
 
-  const bank = new TalerCoreBankHttpClient(
-    url.href,
-    httpLib,
-    evictors.bank,
-  );
+  const bank = new TalerCoreBankHttpClient(url.href, httpLib, evictors.bank);
   const conversion = new TalerBankConversionHttpClient(
     bank.getConversionInfoAPI().href,
     httpLib,
@@ -170,32 +173,36 @@ function buildBankApiClient(url: URL, evictors: Evictors,
       httpLib,
     );
 
-  async function getRemoteConfig() {
-    const resp = await bank.getConfig()
-    return resp.body
+  async function getRemoteConfig(): Promise<TalerCorebankApi.Config> {
+    const resp = await bank.getConfig();
+    if (resp.type === "fail") {
+      throw TalerError.fromUncheckedDetail(resp.detail);
+    }
+    return resp.body;
   }
 
   return {
     getRemoteConfig,
     VERSION: bank.PROTOCOL_VERSION,
     lib: {
-      bank, conversion, auth
+      bank,
+      conversion,
+      auth,
     },
     onActivity: tracker.subscribe,
     cancelRequest: httpLib.cancelRequest,
   };
 }
 
-
 export const BankApiProviderTesting = ({
   children,
   value,
 }: {
-  value: BankContextType
+  value: BankContextType;
   children: ComponentChildren;
 }): VNode => {
   return h(BankContext.Provider, {
     value,
     children,
   });
-}
+};
diff --git a/packages/web-util/src/context/merchant-api.ts 
b/packages/web-util/src/context/merchant-api.ts
index 9e2869b62..26d9c9e85 100644
--- a/packages/web-util/src/context/merchant-api.ts
+++ b/packages/web-util/src/context/merchant-api.ts
@@ -23,7 +23,6 @@ import {
   TalerError,
   TalerMerchantApi,
   TalerMerchantInstanceCacheEviction,
-  TalerMerchantInstanceHttpClient,
   TalerMerchantManagementCacheEviction,
   TalerMerchantManagementHttpClient,
 } from "@gnu-taler/taler-util";
@@ -35,14 +34,13 @@ import {
   h,
 } from "preact";
 import { useContext, useEffect, useState } from "preact/hooks";
+import { BrowserFetchHttpLib } from "../index.browser.js";
 import {
   APIClient,
   ActiviyTracker,
   MerchantLib,
   Subscriber,
 } from "./activity.js";
-import { useTranslationContext } from "./translation.js";
-import { BrowserFetchHttpLib, ErrorLoading } from "../index.browser.js";
 
 /**
  *
@@ -56,6 +54,7 @@ export type MerchantContextType = {
   hints: VersionHint[];
   onActivity: Subscriber<ObservabilityEvent>;
   cancelRequest: (eventId: string) => void;
+  changeBackend: (url: URL) => void;
 };
 
 // FIXME: below
@@ -94,14 +93,17 @@ export const MerchantApiProvider = ({
   baseUrl: URL;
   evictors?: Evictors;
   children: ComponentChildren;
-  frameOnError: FunctionComponent<{ state: 
ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined }>;
+  frameOnError: FunctionComponent<{
+    state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined;
+  }>;
 }): VNode => {
   const [checked, setChecked] =
     useState<ConfigResult<TalerMerchantApi.VersionResponse>>();
-  const { i18n } = useTranslationContext();
+
+  const [merchantEndpoint, changeMerchantEndpoint] = useState(baseUrl);
 
   const { getRemoteConfig, VERSION, lib, cancelRequest, onActivity } =
-    buildMerchantApiClient(baseUrl, evictors);
+    buildMerchantApiClient(merchantEndpoint, evictors);
 
   useEffect(() => {
     getRemoteConfig()
@@ -128,11 +130,12 @@ export const MerchantApiProvider = ({
   }
 
   const value: MerchantContextType = {
-    url: baseUrl,
+    url: merchantEndpoint,
     config: checked.config,
     onActivity: onActivity,
     lib,
     cancelRequest,
+    changeBackend: changeMerchantEndpoint,
     hints: checked.hints,
   };
   return h(MerchantContext.Provider, {
@@ -157,40 +160,51 @@ function buildMerchantApiClient(
     },
   });
 
-  const management = new TalerMerchantManagementHttpClient(
+  const instance = new TalerMerchantManagementHttpClient(
     url.href,
     httpLib,
     evictors.management,
   );
-  const instance = (instanceId: string) =>
-    new TalerMerchantInstanceHttpClient(
-      management.getSubInstanceAPI(instanceId).href,
-      httpLib,
-      evictors.instance ? evictors.instance(instanceId) : undefined,
-    );
   const authenticate = new TalerAuthenticationHttpClient(
-    management.getAuthenticationAPI().href,
+    instance.getAuthenticationAPI().href,
     httpLib,
   );
-  const impersonate = (instanceId: string) =>
-    new TalerAuthenticationHttpClient(
-      instance(instanceId).getAuthenticationAPI().href,
-      httpLib,
-    );
+
+  // const instance = (instanceId: string): TalerMerchantInstanceHttpClient => 
{
+  //   return new TalerMerchantInstanceHttpClient(
+  //     management.getSubInstanceAPI(instanceId).href,
+  //     httpLib,
+  //     evictors.instance ? evictors.instance(instanceId) : undefined,
+  //   );
+  // }
+  // const impersonate = (instanceId: string): TalerAuthenticationHttpClient 
=> {
+  //   return new TalerAuthenticationHttpClient(
+  //     instance(instanceId).getAuthenticationAPI().href,
+  //     httpLib,
+  //   );
+  // }
+  const rootUrl = url;
+  function getSubInstanceAPI(instanceId: string): MerchantLib {
+    const newURL = new URL(`instance/${instanceId}/`, rootUrl);
+    const api = buildMerchantApiClient(newURL, evictors);
+    return api.lib;
+  }
 
   async function getRemoteConfig(): Promise<TalerMerchantApi.VersionResponse> {
-    const resp = await management.getConfig();
+    const resp = await instance.getConfig();
+    if (resp.type === "fail") {
+      throw TalerError.fromUncheckedDetail(resp.detail)
+    }
     return resp.body;
   }
 
   return {
     getRemoteConfig,
-    VERSION: management.PROTOCOL_VERSION,
+    VERSION: instance.PROTOCOL_VERSION,
     lib: {
-      management,
-      authenticate,
-      impersonate,
       instance,
+      authenticate,
+      subInstanceApi: getSubInstanceAPI,
     },
     onActivity: tracker.subscribe,
     cancelRequest: httpLib.cancelRequest,
diff --git a/packages/web-util/src/utils/http-impl.sw.ts 
b/packages/web-util/src/utils/http-impl.sw.ts
index 4d7f3a8a1..3c4b8b587 100644
--- a/packages/web-util/src/utils/http-impl.sw.ts
+++ b/packages/web-util/src/utils/http-impl.sw.ts
@@ -18,11 +18,10 @@
  * Imports.
  */
 import {
+  Duration,
   RequestThrottler,
-  TalerErrorCode,
   TalerError,
-  Duration,
-  CancellationToken,
+  TalerErrorCode
 } from "@gnu-taler/taler-util";
 
 import {

-- 
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]